home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-02 | 114.9 KB | 2,731 lines | [TEXT/CCL2] |
- ;;;-*- Mode: Lisp; Package: (WOOD) -*-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; persistent-heap.lisp
- ;; Code to maintain a Lisp heap in a file.
- ;;
- ;; Copyright © 1992 Apple Computer, Inc. All rights reserved.
- ;; Permission is given to use, copy, and modify this software provided
- ;; that this copyright notice is attached to all derivative works.
- ;; This software is provided "as is". Apple makes no warranty or
- ;; representation, either express or implied, with respect to this software,
- ;; its quality, accuracy, merchantability, or fitness for a particular
- ;; purpose.
- ;;
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Modification History
- ;;
- ;; -------------- 0.5
- ;; 07/27/92 bill p-clrhash, p-maphash
- ;; 06/23/92 bill (open-pheap name :if-exists :supersede) now works
- ;; 06/04/92 bill save/restore functions
- ;; 06/23/92 bill save/restore CLOS instances -> persistent-clos.lisp
- ;; -------------- 0.1
- ;;
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; To do.
- ;;
- ;; Hook for writing/reading macptr's
- ;;
- ;; Make abort in the middle of load or store clear the cache appropriately.
- ;;
- ;; p-maphash, p-map-btree
- ;;
- ;; persistent-stream
- ;;
- ;; Think about floats. The current implementation does not allow
- ;; for distinguishing floats and conses when walking memory.
- ;; 1) A float is a 16-byte vector. Free up the tag
- ;; 2) Cons floats in a special area.
- ;; 3) Don't worry about being able to walk memory.
-
- (defpackage :wood)
- (in-package :wood)
-
- (export '(create-pheap open-pheap close-pheap with-open-pheap
- root-object p-load p-store
- ))
-
- (eval-when (:compile-toplevel :execute)
- (require :woodequ)
- (require :lispequ))
-
- (defclass pheap ()
- ((disk-cache :accessor pheap-disk-cache :initarg :disk-cache)
- (consing-area :accessor pheap-consing-area :initarg :consing-area)
- (pptr-hash :accessor pptr-hash
- :initform (make-hash-table :weak :value :test 'eql))
- (wrapper-hash :accessor wrapper-hash
- :initform (make-hash-table :weak :key :test 'eq))
- (pheap->mem-hash :accessor pheap->mem-hash
- :initform (make-hash-table :weak :value :test 'eq))
- (mem->pheap-hash :accessor mem->pheap-hash
- :initform (make-hash-table :weak :key :test 'eq))
- (p-load-hash :accessor p-load-hash
- :initform (make-hash-table :weak :key :test 'eq))
- (inside-p-load :accessor inside-p-load :initform nil)
- (p-store-hash :accessor p-store-hash
- :initform (make-hash-table :weak :key :test 'eq))
- (inside-p-store :accessor inside-p-store :initform nil)))
-
-
- ; A PPTR is a pointer into a PHEAP
- (defstruct (pptr (:print-function print-pptr))
- pheap
- pointer
- )
-
- (defun print-pptr (pptr stream level)
- (declare (ignore level))
- (write-string "#.(" stream)
- (prin1 'pptr stream)
- (tyo #\space stream)
- (prin1 (pptr-pheap pptr) stream)
- (write-string " #x" stream)
- (let ((*print-base* 16))
- (prin1 (pptr-pointer pptr) stream))
- (tyo #\) stream))
-
- (defun pptr (pheap pointer)
- (if (eq pointer $pheap-nil)
- nil
- (let ((hash (pptr-hash pheap)))
- (or (gethash pointer hash)
- (setf (gethash pointer hash)
- (make-pptr :pheap pheap :pointer pointer))))))
-
- ; Turns a value into a (pointer imm?) pair
- (defun split-pptr (maybe-pptr)
- (if (pptr-p maybe-pptr)
- (pptr-pointer maybe-pptr)
- (values maybe-pptr t)))
-
- (defun dc-pointer-pptr (disk-cache pointer)
- (pptr (disk-cache-pheap disk-cache) pointer))
-
- (defun pptr-disk-cache (pptr)
- (pheap-disk-cache (pptr-pheap pptr)))
-
- (defconstant $version-number #x504801) ; current version number "PH1"
- (defconstant $min-version #x504801) ; minimum version number we can deal with
- (defconstant $max-version #x504801) ; maximum version number we can deal with
-
- (defparameter *default-area-segment-size* 4096)
- (defparameter *default-page-size* 512)
- (defparameter *default-max-pages* 200)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Functions to create, open, and close pheaps
- ;;
-
- (defmacro dc-%svfill (disk-cache vector &body indices-and-values)
- (let (res)
- (loop
- (when (null indices-and-values) (return))
- (let ((index (pop indices-and-values))
- (value (pop indices-and-values))
- immediate?)
- (when (consp index)
- (psetq index (car index) immediate? (cadr index)))
- (push `(setf (dc-%svref ,disk-cache ,vector ,index ,immediate?) ,value)
- res)))
- `(progn ,@(nreverse res))))
-
- ; Create a pheap. Close its file.
- (defun create-pheap (filename &key
- (if-exists :error)
- (area-segment-size *default-area-segment-size*)
- (page-size *default-page-size*))
- (let ((min-page-size 512))
- (setq page-size
- (require-type (* min-page-size (floor (+ page-size min-page-size -1) min-page-size))
- 'fixnum)))
- (let* ((disk-cache (open-disk-cache
- filename
- :if-exists if-exists
- :if-does-not-exist :create
- :page-size page-size
- :external-format :WOOD)))
- (fill-long disk-cache 0 0 (ash (disk-cache-page-size disk-cache) -2))
- (initialize-vector-storage
- disk-cache (pointer-address $root-vector)
- $pheap-header-size $v_dbheader 4 $pheap-nil)
- (dc-%svfill disk-cache $root-vector
- ($pheap.version t) $version-number
- ($pheap.free-page t) 1
- $pheap.default-consing-area (dc-make-area
- disk-cache :segment-size area-segment-size)
- ($pheap.page-size t) page-size)
- (setf (read-string disk-cache
- (+ $root-vector (- $t_vector) (ash $pheap-header-size 2)))
- #.(format nil "~%This is a persistent heap~%~
- created by William's Object Oriented Database~%~
- in Macintosh Common Lisp.~%"))
- (close-disk-cache disk-cache)
- filename))
-
- (defvar *open-pheaps* nil)
-
- (defun open-pheap (filename &rest rest
- &key
- (if-does-not-exist :error)
- (if-exists :overwrite)
- (area-segment-size *default-area-segment-size*)
- (page-size *default-page-size*)
- (max-pages (ceiling (* *default-page-size*
- *default-max-pages*)
- page-size)))
- (declare (dynamic-extent rest))
- (let* ((disk-cache (unless (eq if-exists :supersede)
- (open-disk-cache filename
- :if-exists if-exists
- :if-does-not-exist nil
- :page-size page-size
- :max-pages max-pages
- :write-hook 'pheap-write-hook
- :external-format :WOOD))))
- (when (null disk-cache)
- (if (or (eq if-exists :supersede)
- (eq if-does-not-exist :create))
- (progn
- (create-pheap filename
- :if-exists if-exists
- :area-segment-size area-segment-size
- :page-size page-size)
- (return-from open-pheap
- (apply #'open-pheap filename :if-exists :overwrite rest)))
- (error "File ~s does not exist" filename)))
- (when (not (eql page-size (setq page-size (dc-%svref disk-cache $root-vector $pheap.page-size))))
- (close-disk-cache disk-cache)
- (return-from open-pheap
- (apply #'open-pheap filename :page-size page-size rest)))
- (let ((done? nil))
- (unwind-protect
- (progn
- (lock-page-at-address disk-cache 0) ; accessed frequently
- (multiple-value-bind (count imm?) (dc-page-write-count disk-cache)
- (when (or imm? (not (eql count $pheap-nil)))
- (cerror "Hope for the best."
- "~s was modified but not closed properly. It may be corrupt."
- filename)
- (setf (dc-page-write-count disk-cache) $pheap-nil
- (disk-cache-write-hook disk-cache) nil)
- (flush-disk-cache disk-cache)
- (setf (disk-cache-write-hook disk-cache) 'pheap-write-hook)))
- (let ((pheap (make-instance 'pheap :disk-cache disk-cache)))
- (setf (pheap-consing-area pheap) (dc-default-consing-area disk-cache))
- (push pheap *open-pheaps*)
- (setq done? t)
- pheap))
- (unless done?
- (close-disk-cache disk-cache))))))
-
- (defun close-pheap (pheap)
- (flush-pheap pheap)
- (close-disk-cache (pheap-disk-cache pheap))
- (setq *open-pheaps* (delq pheap *open-pheaps*))
- nil)
-
- (defmacro with-open-pheap ((pheap filename &rest options) &body body)
- `(let ((,pheap (open-pheap ,filename ,@options)))
- (unwind-protect
- (progn ,@body)
- (close-pheap ,pheap))))
-
- (defun disk-cache-pheap (disk-cache)
- (dolist (pheap *open-pheaps*)
- (if (eq disk-cache (pheap-disk-cache pheap))
- (return pheap))))
-
- (defun flush-pheap (pheap)
- (let ((disk-cache (pheap-disk-cache pheap)))
- (flush-disk-cache disk-cache)
- (multiple-value-bind (count imm?) (dc-page-write-count disk-cache)
- (unless (and (not imm?) (eql count $pheap-nil))
- (setf (dc-page-write-count disk-cache) $pheap-nil
- (disk-cache-write-hook disk-cache) nil)
- (flush-disk-cache disk-cache)
- (setf (disk-cache-write-hook disk-cache) 'pheap-write-hook)))))
-
- (defun flush-all-open-pheaps ()
- (dolist (pheap *open-pheaps*)
- (flush-pheap pheap)))
-
- (pushnew 'flush-all-open-pheaps *lisp-cleanup-functions*)
-
- ; This marks the pheap as modifed so that the next open
- ; will complain if it was not closed properly.
- ; Eventually, we'll also maintain an active transactions count.
- (defun pheap-write-hook (disk-page)
- (let ((disk-cache (disk-page-disk-cache disk-page))
- flush-page-0?)
- (multiple-value-bind (count imm?) (dc-page-write-count disk-cache)
- (when (and (not imm?) (eql count $pheap-nil))
- (setq count 0
- flush-page-0? t))
- (setf (dc-page-write-count disk-cache t)
- (if (eql count most-positive-fixnum)
- count
- (1+ count)))
- (when flush-page-0?
- (setf (disk-cache-write-hook disk-cache) nil)
- (flush-disk-page (nth-value 3 (get-disk-page disk-cache 0)))
- (setf (disk-cache-write-hook disk-cache) 'pheap-write-hook)))))
-
- (defun dc-page-write-count (disk-cache)
- (dc-%svref disk-cache $root-vector $pheap.page-write-count))
-
- (defun (setf dc-page-write-count) (value disk-cache &optional imm?)
- (setf (dc-%svref disk-cache $root-vector $pheap.page-write-count imm?)
- value))
-
- (defun pheap-default-consing-area (pheap)
- (multiple-value-bind (pointer immediate?)
- (dc-default-consing-area (pheap-disk-cache pheap))
- (if immediate?
- pointer
- (pptr pheap pointer))))
-
- (defun dc-default-consing-area (disk-cache)
- (dc-%svref disk-cache
- $root-vector
- $pheap.default-consing-area))
-
- (defmacro require-satisfies (predicate &rest args)
- `(unless (,predicate ,@args)
- (error "Not ~s" ',predicate)))
-
- (defun (setf pheap-default-consing-area) (area pheap)
- (let ((disk-cache (pheap-disk-cache pheap))
- (pointer (pheap-pptr-pointer area pheap)))
- (require-satisfies dc-vector-subtype-p disk-cache pointer $v_area)
- (setf (dc-%svref disk-cache $root-vector $pheap.default-consing-area)
- pointer))
- area)
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Reading pheap data into the Lisp heap
- ;;
- ;; Readers take a DEPTH argument:
- ;; :default The default. Load the object into memory stopping at
- ;; objects that have already been loaded.
- ;; nil No conversion except lookup in the hash table.
- ;; :single load a single level. vectors, arrays, & lists will come out
- ;; one level deep. May cons lots of pptr's
- ;; <fixnum> Same as :single but will only load vectors if their length
- ;; is <= depth
- ;; T Recursive descent until closure. May modify some existing Lisp objects.
- ;; Slower than the others as it requires clearing the descent hash table.
-
-
- (defun root-object (pheap)
- (multiple-value-bind (pointer immediate?)
- (dc-%svref (pheap-disk-cache pheap) $root-vector $pheap.root)
- (if immediate?
- pointer
- (pptr pheap pointer))))
-
-
- (defun p-load (pptr &optional (depth :default))
- (if (pptr-p pptr)
- (pointer-load (pptr-pheap pptr)
- (pptr-pointer pptr)
- depth)
- pptr))
-
- (defun pointer-load (pheap pointer &optional depth disk-cache)
- (unless disk-cache
- (setq disk-cache (pheap-disk-cache pheap)))
- (if (or (neq depth t) (inside-p-load pheap))
- (pointer-load-internal pheap pointer depth disk-cache)
- (unwind-protect
- (progn
- (setf (inside-p-load pheap) t)
- (pointer-load-internal pheap pointer depth disk-cache))
- (clrhash (p-load-hash pheap))
- (setf (inside-p-load pheap) nil))))
-
- (defun pointer-load-internal (pheap pointer depth disk-cache)
- (let ((tag (pointer-tag pointer)))
- (declare (fixnum tag))
- (let ((f (locally (declare (optimize (speed 3) (safety 0)))
- (svref #(p-load-immediate ; $t_fixnum
- p-load-vector ; $t_vector
- p-load-symbol ; $t_symbol
- p-load-dfloat ; $t_dfloat
- p-load-cons ; $t_cons
- p-load-immediate ; $t_sfloat
- p-load-lfun ; $t_lfun
- p-load-immediate) ; $t_imm
- tag))))
- (unless (or (eq depth t) (eq f 'p-load-immediate))
- (let ((res (gethash pointer (pheap->mem-hash pheap))))
- (when res
- (return-from pointer-load-internal res))))
- (funcall f pheap disk-cache pointer depth))))
-
- ; For error messages
- (defun dc-pointer-load (disk-cache pointer &optional immediate? pheap)
- (if immediate?
- pointer
- (pointer-load (or pheap (disk-cache-pheap disk-cache)) pointer :default disk-cache)))
-
- (defmacro maybe-cached-value (pheap pointer &body forms)
- (setq pheap (require-type pheap 'symbol)
- pointer (require-type pointer '(or symbol integer)))
- (let ((pheap->mem-hash (make-symbol "PHEAP->MEM-HASH"))
- (value (make-symbol "VALUE")))
- `(let ((,pheap->mem-hash (pheap->mem-hash ,pheap)))
- (or (gethash ,pointer ,pheap->mem-hash)
- (let ((,value (progn ,@forms)))
- (if (pptr-p ,value) ; you should throw out in this case.
- ,value
- (setf (gethash ,value (mem->pheap-hash ,pheap)) ,pointer
- (gethash ,pointer ,pheap->mem-hash) ,value)))))))
-
- (defmacro maybe-cached-address (pheap object &body forms)
- (setq pheap (require-type pheap 'symbol)
- object (require-type object 'symbol))
- (let ((mem->pheap-hash (make-symbol "MEM->PHEAP-HASH"))
- (address (make-symbol "ADDRESS")))
- `(let ((,mem->pheap-hash (mem->pheap-hash ,pheap)))
- (or (gethash ,object ,mem->pheap-hash)
- (let ((,address (progn ,@forms)))
- (setf (gethash ,address (pheap->mem-hash ,pheap)) ,object
- (gethash ,object ,mem->pheap-hash) ,address))))))
-
- (defun p-load-immediate (pheap disk-cache pointer depth)
- (declare (ignore disk-cache depth))
- (error "Immediate pointer ~s" (pptr pheap pointer)))
-
- (defparameter *p-load-subtype-functions*
- #(p-load-error ;($v_packed_sstr 0)
- p-load-ivector ;($v_bignum 1)
- p-load-error ;($v_macptr 2) - not supported
- p-load-ivector ;($v_badptr 3)
- p-load-lfun-vector ;($v_nlfunv 4)
- p-load-error ;subtype 5 unused
- p-load-error ;subtype 6 unused
- p-load-ivector ;($v_ubytev 7) ;unsigned byte vector
- p-load-ivector ;($v_uwordv 8) ;unsigned word vector
- p-load-ivector ;($v_floatv 9) ;float vector
- p-load-ivector ;($v_slongv 10) ;Signed long vector
- p-load-ivector ;($v_ulongv 11) ;Unsigned long vector
- p-load-ivector ;($v_bitv 12) ;Bit vector
- p-load-ivector ;($v_sbytev 13) ;Signed byte vector
- p-load-ivector ;($v_swordv 14) ;Signed word vector
- p-load-ivector ;($v_sstr 15) ;simple string
- p-load-gvector ;($v_genv 16) ;simple general vector
- p-load-header ;($v_arrayh 17) ;complex array header
- p-load-istruct ;($v_struct 18) ;structure
- p-load-error ;($v_mark 19) ;buffer mark
- p-load-pkg ;($v_pkg 20)
- p-load-error ;subtype 21 unused
- p-load-istruct ;($v_istruct 22)
- p-load-ivector ;($v_ratio 23)
- p-load-ivector ;($v_complex 24)
- p-load-instance ;($v_instance 25) ;clos instance
- p-load-error ;subtype 26 unused
- p-load-error ;subtype 27 unused
- p-load-error ;subtype 28 unused
- p-load-header ;($v_weakh 29)
- p-load-header ;($v_poolfreelist 30)
- p-load-header ;($v_nhash 31)
- ; internal subtypes
- p-load-nop ;($v_area 32)
- p-load-nop ;($v_segment 33)
- p-load-nop ;($v_random-bits 34)
- p-load-nop ;($v_dbheader 35)
- p-load-nop ;($v_segment-headers 36)
- p-load-nop ;($v_btree 37)
- p-load-nop ;($v_btree-node 38)
- p-load-class ;($v_class 39)
- ))
-
- (defun p-load-vector (pheap disk-cache pointer depth)
- (let ((subtype (dc-%vector-subtype disk-cache pointer)))
- (declare (fixnum subtype))
- (let ((f (svref *p-load-subtype-functions* subtype)))
- (if f
- (funcall f pheap disk-cache pointer depth subtype)
- (pptr pheap pointer)))))
-
- (defun p-load-error (pheap disk-cache pointer depth subtype)
- (declare (ignore disk-cache depth))
- (error "~x is of unsupported subtype: ~s" (pptr pheap pointer) subtype))
-
- (defun p-load-nop (pheap disk-cache pointer depth subtype)
- (declare (ignore disk-cache depth subtype))
- (pptr pheap pointer))
-
-
- (defmacro wood->ccl-subtype (wood-subtype)
- `(* 2 ,wood-subtype))
-
- (defmacro ccl->wood-subtype (ccl-subtype)
- `(ash ,ccl-subtype -1))
-
-
- ; general vector
- (defun p-load-gvector (pheap disk-cache pointer depth subtype &optional
- special-index-p special-index-value)
- (let* (length
- (cached? t)
- (vector (maybe-cached-value pheap pointer
- (setq cached? nil
- length (dc-%simple-vector-length disk-cache pointer))
- (if (or (null depth)
- (and (fixnump depth) (< depth length)))
- (return-from p-load-gvector (pptr pheap pointer))
- (ccl::%make-uvector length (wood->ccl-subtype subtype))))))
- (when (or (not cached?)
- (listp depth)
- (and (eq depth t)
- (let ((p-load-hash (p-load-hash pheap)))
- (unless (gethash vector p-load-hash)
- (setf (gethash vector p-load-hash) vector)))))
- (let ((next-level-depth (cond ((or (eq depth :single) (fixnump depth)) nil)
- ((listp depth) (car depth))
- (t depth))))
- (dotimes (i (or length (uvsize vector)))
- (setf (uvref vector i)
- (if (and special-index-p (funcall special-index-p i))
- (funcall special-index-value disk-cache pointer i)
- (multiple-value-bind (pointer immediate?)
- (dc-%svref disk-cache pointer i)
- (if immediate?
- pointer
- (pointer-load pheap pointer next-level-depth disk-cache))))))))
- vector))
-
- (defun p-load-header (pheap disk-cache pointer depth subtype &optional
- special-index-p special-index-value)
- ; (declare (type (integer 0 256) subtype))
- (if (eq depth t)
- (p-load-gvector pheap disk-cache pointer depth subtype
- special-index-p special-index-value)
- (let ((depth-list (list depth)))
- (declare (dynamic-extent depth-list))
- (p-load-gvector pheap disk-cache pointer depth-list subtype
- special-index-p special-index-value))))
-
- (defun p-load-istruct (pheap disk-cache pointer depth subtype)
- (declare (dynamic-extent #'special-index-value))
- (p-load-gvector pheap disk-cache pointer depth subtype
- #'(lambda (index) (eql index 0))
- #'(lambda (disk-cache pointer index)
- (multiple-value-bind (p imm?) (dc-%svref disk-cache pointer index)
- (if imm?
- p
- (pointer-load (disk-cache-pheap disk-cache)
- p
- :default
- disk-cache))))))
-
- (defparameter *subtype->bytes-per-element*
- #(nil ; 0 - unused
- 2 ; 1 - $v_bignum
- nil ; 2 - $v_macptr - not supported
- 4 ; 3 - $v_badptr
- 2 ; 4 - $v_nlfunv
- nil ; 5 - unused
- nil ; 6 - unused
- 1 ; 7 - $v_ubytev - unsigned byte vector
- 2 ; 8 - $v_uwordv - unsigned word vector
- 8 ; 9 - $v_floatv - float vector
- 4 ; 10 - $v_slongv - Signed long vector
- 4 ; 11 - $v_ulongv - Unsigned long vector
- nil ; 12 - $v_bitv - Bit vector (handled specially)
- 1 ; 13 - $v_sbytev - Signed byte vector
- 2 ; 14 - $v_swordv - Signed word vector
- 1 ; 15 - $v_sstr - simple string
- 4 ; 16 - $v_genv - simple general vector
- 4 ; 17 - $v_arrayh - complex array header
- 4 ; 18 - $v_struct - structure
- nil ; 19 - $v_mark - buffer mark unimplemented
- 4 ; 20 - $v_pkg
- nil ; 21 - unused
- 4 ; 22 - $v_istruct - type in first element
- 4 ; 23 - $v_ratio
- 4 ; 24 - $v_complex
- 4 ; 25 - $v_instance - clos instance
- nil ; 26 - unused
- nil ; 27 - unused
- nil ; 28 - unused
- 4 ; 29 - $v_weakh - weak list header
- 4 ; 30 - $v_poolfreelist - free pool header
- 4 ; 31 - $v_nhash
- ; WOOD specific subtypes
- 4 ; 32 - $v_area - area descriptor
- 4 ; 33 - $v_segment - area segment
- 1 ; 34 - $v_random-bits - vectors of random bits, e.g. resources
- 4 ; 35 - $v_dbheader - database header
- nil ; 36 - $v_segment-headers - specially allocated
- 4 ; 37 - $v_btree
- nil ; 38 - $v_btree-node - specially allocated
- 4 ; 39 - $v_class
- ))
-
- ; ivectors
- (defun p-load-ivector (pheap disk-cache pointer depth subtype)
- (declare (fixnum subtype))
- (let* ((cached? t)
- (res (maybe-cached-value pheap pointer
- (setq cached? nil)
- (let ((length (dc-uvsize disk-cache pointer))
- (size (dc-%vector-size disk-cache pointer)))
- (if (and depth
- (or (not (fixnump depth)) (<= length depth)))
- (load-byte-array
- disk-cache (addr+ disk-cache pointer $v_data) size
- (ccl::%make-uvector length (wood->ccl-subtype subtype))
- 0 t)
- (return-from p-load-ivector (pptr pheap pointer)))))))
- (when (and cached? (eq depth t))
- (let* ((size (dc-%vector-size disk-cache pointer))
- (subtype (dc-%vector-subtype disk-cache pointer)))
- (unless (eql (uvsize res) (dc-uvsize disk-cache pointer))
- (error "Inconsistency. Disk ivector is different size than in-memory version."))
- (unless (eql (wood->ccl-subtype subtype)
- (ccl::%vect-subtype res))
- (error "Inconsistency. Subtype mismatch."))
- (load-byte-array disk-cache (addr+ disk-cache pointer $v_data) size res 0 t)))
- res))
-
- (defun p-load-lfun-vector (pheap disk-cache pointer depth subtype)
- (declare (ignore pheap disk-cache pointer depth subtype))
- (error "Inconsitency: WOOD does not tag vectors as ~s" '$t_lfunv))
-
- (defun p-load-pkg (pheap disk-cache pointer depth subtype)
- (declare (ignore depth subtype))
- (maybe-cached-value pheap pointer
- (let* ((names (pointer-load-internal pheap (dc-%svref disk-cache pointer $pkg.names)
- t disk-cache))
- (name (car names)))
- (or (find-package name)
- (make-package name :nicknames (cdr names) :use nil)))))
-
- ;; End of loaders for $t_vector subtypes
-
- (defun p-load-symbol (pheap disk-cache pointer depth)
- (declare (ignore depth))
- (maybe-cached-value pheap pointer
- (intern (pointer-load-internal
- pheap (read-long disk-cache (+ pointer $sym_pname)) :default disk-cache)
- (pointer-load-internal
- pheap (read-long disk-cache (+ pointer $sym_package)) :default disk-cache))))
-
- (defun p-load-dfloat (pheap disk-cache pointer depth)
- (maybe-cached-value pheap pointer
- (if (eq depth nil)
- (return-from p-load-dfloat (pptr pheap pointer)))
- (values (read-double-float disk-cache (- pointer $t_dfloat)) t)))
-
- (defun p-load-cons (pheap disk-cache pointer depth)
- (declare (ignore subtype))
- (if (eql pointer $pheap-nil)
- nil
- (let* ((cached? t)
- (cons (maybe-cached-value pheap pointer
- (setq cached? nil)
- (if (or (null depth) (and (fixnump depth) (<= depth 0)))
- (return-from p-load-cons (pptr pheap pointer))
- (cons nil nil)))))
- (when (or (not cached?)
- (and (eq depth t)
- (let ((p-load-hash (p-load-hash pheap)))
- (unless (gethash cons p-load-hash)
- (setf (gethash cons p-load-hash) cons)))))
- (let ((next-level-depth (unless (or (eq depth :single) (fixnump depth))
- depth))
- (rest-depth (if (fixnump depth) (1- depth) depth)))
- (multiple-value-bind (car car-imm?) (read-pointer disk-cache (- pointer $t_cons))
- (multiple-value-bind (cdr cdr-imm?) (read-pointer disk-cache pointer)
- (setf (car cons)
- (if car-imm?
- car
- (pointer-load pheap car next-level-depth disk-cache)))
- (setf (cdr cons)
- (if cdr-imm?
- cdr
- (pointer-load pheap cdr rest-depth disk-cache)))))))
- cons)))
-
- (defun p-load-lfun (pheap disk-cache pointer depth)
- (maybe-cached-value pheap pointer
- (if (null depth)
- (return-from p-load-lfun (pptr pheap pointer))
- (let* ((vector-pointer (+ pointer (- $t_vector $t_lfun)))
- (vector (p-load-vector pheap disk-cache vector-pointer :default)))
- (ccl::applyv #'join-lfun vector)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Writing Lisp data into the pheap
- ;;;
-
- ;;; The descend argument can take three values:
- ;;;
- ;;; :default The default. Don't descend if you find an address in the cache
- ;;; nil Same as :default, but newly consed values are not cached.
- ;;; Allows storing stack-consed objects in the persistent heap.
- ;;; t Recursively descend and overwrite any cached values.
-
- (defun (setf root-object) (new-root pheap)
- (multiple-value-bind (pointer immediate?) (%p-store pheap new-root)
- (setf (dc-%svref (pheap-disk-cache pheap) $root-vector $pheap.root immediate?)
- pointer)
- (if immediate?
- pointer
- (pptr pheap pointer))))
-
- (defun p-store (pheap object &optional (descend :default))
- (multiple-value-bind (pointer immediate?) (%p-store pheap object descend)
- (if (or immediate? (null pointer))
- pointer
- (pptr pheap pointer))))
-
- (defun require-pptr-pheap (pptr pheap)
- (unless (eq (pptr-pheap pptr) pheap)
- (error "wrong pheap!")))
-
- (defun pheap-pptr-pointer (pptr pheap)
- (require-pptr-pheap pptr pheap)
- (pptr-pointer pptr))
-
- (defun %p-store (pheap object &optional (descend :default))
- (unless (or (eq descend :default)
- (null descend)
- (eq descend t))
- (setq descend (require-type descend '(member :default nil t))))
- (cond ((ccl::dtagp object (+ (ash 1 ccl::$t_fixnum)
- (ash 1 ccl::$t_sfloat)
- (ash 1 ccl::$t_imm)))
- (values object t))
- ((typep object 'pptr)
- (require-pptr-pheap object pheap)
- (pptr-pointer object))
- (t (if (or (eq descend :default) (inside-p-store pheap))
- (%p-store-internal pheap object descend)
- (unwind-protect
- (progn
- (setf (inside-p-store pheap) t)
- (%p-store-internal pheap object descend))
- (clrhash (p-store-hash pheap))
- (setf (inside-p-store pheap) nil))))))
-
- (defun %p-store-internal (pheap object descend)
- (if (ccl::dtagp object (logior (ash 1 ccl::$t_fixnum)
- (ash 1 ccl::$t_sfloat)
- (ash 1 ccl::$t_imm)))
- (values object t)
- (or (and (neq descend t) (gethash object (p-store-hash pheap)))
- (%p-store-object pheap object descend))))
-
- (defmethod %p-store-object (pheap (object pptr) descend)
- (declare (ignore descend))
- (require-pptr-pheap object pheap)
- (pptr-pointer object))
-
- (defmethod %p-store-object (pheap (object symbol) descend)
- (if (null object)
- $pheap-nil
- (maybe-cached-address pheap object
- (let ((address (dc-intern (pheap-disk-cache pheap)
- (symbol-name object)
- (symbol-package object)
- t
- (pheap-consing-area pheap)
- pheap)))
- (when (eq descend nil)
- (return-from %p-store-object address))
- address))))
-
- (defmethod %p-store-object (pheap (object null) descend)
- (declare (ignore pheap descend))
- $pheap-nil)
-
- (defmethod %p-store-object (pheap (object function) descend)
- (declare (ignore descend))
- (maybe-cached-address pheap object
- (let* ((split-vec (apply #'vector (split-lfun object)))
- (address (%p-store pheap split-vec)))
- (+ address (- $t_lfun $t_vector)))))
-
- ; This happenned three times so I made it into a macro.
- (defmacro %p-store-object-body ((pheap object descend disk-cache address)
- &body body)
- (unless (null (cddr body))
- (error "body must be of the form (conser filler)"))
- (let ((conser (car body))
- (filler (cadr body))
- (conser-var (gensym))
- (filler-var (gensym)))
- `(let ((,conser-var #'(lambda (,disk-cache ,object)
- (declare (ignore-if-unused ,object))
- ,conser))
- (,filler-var #'(lambda (,pheap ,disk-cache ,object ,address ,descend)
- (declare (ignore-if-unused ,pheap ,descend))
- ,filler)))
- (declare (dynamic-extent ,conser-var ,filler-var))
- (do-%p-store-object-body pheap object descend ,conser-var ,filler-var))))
-
- ; The REMHASH'es below are totally misguided. To do this right,
- ; it needs to be a transaction.
- (defun do-%p-store-object-body (pheap object descend conser filler)
- (let* ((disk-cache (pheap-disk-cache pheap))
- (cached? t)
- (address nil)
- (decache? nil)
- (un-p-store-hash? nil))
- (unwind-protect
- (progn
- (block avoid-p-store-hash
- (setq address (block avoid-cache
- (maybe-cached-address pheap object
- (when (eq descend nil)
- (when (setq address (gethash object (p-store-hash pheap)))
- (setq un-p-store-hash? t)
- (return-from avoid-p-store-hash address)))
- (setq cached? nil
- decache? t)
- (prog1
- (setq address (funcall conser disk-cache object))
- (when (eq descend nil)
- (setq decache? nil)
- (return-from avoid-cache address))))))
- (unless (eq descend :default)
- (let ((p-store-hash (p-store-hash pheap)))
- (unless (and descend (gethash object p-store-hash))
- (setf (gethash object p-store-hash) address)
- (setq un-p-store-hash? t)
- (when (eq descend t)
- (setq cached? nil))))))
- (unless cached?
- (funcall filler pheap disk-cache object address descend))
- (setq decache? nil
- un-p-store-hash? nil))
- (when decache?
- (remhash object (mem->pheap-hash pheap))
- (remhash address (pheap->mem-hash pheap)))
- (when un-p-store-hash?
- (remhash object (p-store-hash pheap))))
- address))
-
- (defmethod %p-store-object (pheap (object cons) descend)
- (%p-store-object-body (pheap object descend disk-cache address)
- (dc-cons disk-cache $pheap-nil $pheap-nil)
- (progn
- (multiple-value-bind (car car-imm?) (%p-store pheap (car object) descend)
- (setf (dc-car disk-cache address car-imm?) car))
- (multiple-value-bind (cdr cdr-imm?) (%p-store pheap (cdr object) descend)
- (setf (dc-cdr disk-cache address cdr-imm?) cdr)))))
-
- (defmethod %p-store-object (pheap (object double-float) descend)
- (maybe-cached-address pheap object
- (let ((address (dc-cons-float (pheap-disk-cache pheap)
- object
- (pheap-consing-area pheap))))
- (when (eq descend nil)
- (return-from %p-store-object address))
- address)))
-
- (defun p-cons-float (pheap float)
- (pptr pheap (dc-cons-float (pheap-disk-cache pheap) float)))
-
- (defun dc-cons-float (disk-cache value &optional area)
- (setq value (require-type value 'float))
- (let ((address (%allocate-storage disk-cache area 8)))
- (setf (read-double-float disk-cache (decf address $t_cons)) value)
- (+ $t_dfloat address)))
-
- (defmethod %p-store-object (pheap (object package) descend)
- (maybe-cached-address pheap object
- (let ((address (dc-find-or-make-package (pheap-disk-cache pheap) object t)))
- (when (eq descend nil)
- (return-from %p-store-object address))
- address)))
-
- (defmethod %p-store-object (pheap (object t) descend)
- (if (uvectorp object)
- (%p-store-uvector pheap object descend)
- (error "Don't know how to store ~s" object)))
-
- (defparameter *p-store-subtype-functions*
- #(nil ;($v_packed_sstr 0)
- p-store-ivector ;($v_bignum 1)
- nil ;($v_macptr 2) - not supported
- p-store-ivector ;($v_badptr 3)
- p-store-lfun-vector ;($v_nlfunv 4)
- nil ;subtype 5 unused
- nil ;subtype 6 unused
- p-store-ivector ;($v_ubytev 7) ;unsigned byte vector
- p-store-ivector ;($v_uwordv 8) ;unsigned word vector
- p-store-ivector ;($v_floatv 9) ;float vector
- p-store-ivector ;($v_slongv 10) ;Signed long vector
- p-store-ivector ;($v_ulongv 11) ;Unsigned long vector
- p-store-ivector ;($v_bitv 12) ;Bit vector
- p-store-ivector ;($v_sbytev 13) ;Signed byte vector
- p-store-ivector ;($v_swordv 14) ;Signed word vector
- p-store-ivector ;($v_sstr 15) ;simple string
- p-store-gvector ;($v_genv 16) ;simple general vector
- p-store-gvector ;($v_arrayh 17) ;complex array header
- p-store-gvector ;($v_struct 18) ;structure
- nil ;($v_mark 19) ;buffer mark
- nil ;($v_pkg 20)
- nil ;subtype 21 unused
- p-store-gvector ;($v_istruct 22)
- p-store-ivector ;($v_ratio 23)
- p-store-ivector ;($v_complex 24)
- nil ;($v_instance 25) ;clos instance
- nil ;subtype 26 unused
- nil ;subtype 27 unused
- nil ;subtype 28 unused
- p-store-gvector ;($v_weakh 29)
- p-store-gvector ;($v_poolfreelist 30)
- p-store-gvector ;($v_nhash 31)
- ))
-
- (defun %p-store-uvector (pheap object descend)
- (let* ((length (uvsize object))
- (subtype (ccl->wood-subtype (ccl::%vect-subtype object)))
- (store-function (or (svref *p-store-subtype-functions* subtype)
- (error "Can't store vector of subtype ~s: ~s" subtype object))))
- (%p-store-object-body (pheap object descend disk-cache address)
- (dc-make-uvector disk-cache length subtype)
- (funcall store-function pheap object descend disk-cache address length))))
-
- (defun p-store-gvector (pheap object descend disk-cache address length)
- (dotimes (i length)
- (multiple-value-bind (element imm?) (%p-store pheap (uvref object i) descend)
- (setf (dc-%svref disk-cache address i imm?) element))))
-
- (defun p-store-ivector (pheap object descend disk-cache address length)
- (declare (ignore pheap descend length))
- (let* ((bytes (dc-%vector-size disk-cache address)))
- (store-byte-array object disk-cache (addr+ disk-cache address $v_data) bytes 0 t)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Useful macros for predicates and accessors
- ;;
-
- (defmacro p-dispatch (p if-pptr otherwise &optional make-pptr? apply?)
- (let ((p (if (listp p) (car p) p))
- (args (if (listp p) (cdr p))))
- (flet ((add-apply (form)
- (if apply?
- `(apply #',(car form) ,@(cdr form))
- form)))
- `(if (typep ,p 'pptr)
- (locally (declare (type pptr ,p) (optimize (speed 3) (safety 0)))
- ,(if make-pptr?
- (let ((pheap (make-symbol "PHEAP"))
- (disk-cache (make-symbol "DISK-CACHE"))
- (pointer (make-symbol "POINTER"))
- (immediate? (make-symbol "IMMEDIATE?")))
- `(let* ((,pheap (pptr-pheap ,p))
- (,disk-cache (pheap-disk-cache ,pheap)))
- (multiple-value-bind (,pointer ,immediate?)
- ,(add-apply
- `(,if-pptr ,disk-cache (pptr-pointer ,p) ,@args))
- (if ,immediate?
- ,pointer
- (pptr ,pheap ,pointer)))))
- (add-apply `(,if-pptr (pptr-disk-cache ,p)
- (pptr-pointer ,p)
- ,@args))))
- ,(add-apply `(,otherwise ,p ,@args))))))
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (defun symbol-append (&rest syms)
- (let ((res (string (pop syms))))
- (loop
- (when (null syms) (return))
- (setq res (concatenate 'string res "-" (string (pop syms)))))
- (intern res))))
-
- (defmacro def-predicate (lisp-predicate (p disk-cache pointer) &body body)
- (let ((p-name (symbol-append 'p lisp-predicate))
- (dc-name (symbol-append 'dc lisp-predicate)))
- `(progn
- (defun ,p-name (,p)
- (p-dispatch ,p ,dc-name ,lisp-predicate))
- (defun ,dc-name (,disk-cache ,pointer)
- ,@body))))
-
- (defmacro def-accessor (lisp-accessor (p . args) (disk-cache pointer)
- &body body)
- (let ((p-name (symbol-append 'p lisp-accessor))
- (dc-name (symbol-append 'dc lisp-accessor))
- (args-sans-keywords (remove lambda-list-keywords args
- :test #'(lambda (ll arg) (memq arg ll))))
- (rest-arg? (let ((l (cdr (memq '&rest args))))
- (when l
- (when (cdr l) (error "rest arg must be last"))
- (car l)))))
- `(progn
- (defun ,p-name (,p ,@args)
- ,@(if rest-arg? `((declare (dynamic-extent ,rest-arg?))))
- (p-dispatch (,p ,@args-sans-keywords)
- ,dc-name ,lisp-accessor t ,rest-arg?))
- (defun ,dc-name (,disk-cache ,pointer ,@args)
- ,@body))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Predicates
- ;;;
-
- ; p-simple-string-p & dc-simple-string-p
- (def-predicate simple-string-p (p disk-cache pointer)
- (dc-vector-subtype-p disk-cache pointer $v_sstr))
-
- ; p-simple-vector-p & dc-simple-vector-p
- (def-predicate simple-vector-p (p disk-cache pointer)
- (dc-vector-subtype-p disk-cache pointer $v_genv))
-
- (defun dc-vector-subtype-p (disk-cache pointer subtype)
- (declare (fixnum subtype))
- (and (pointer-tagp pointer $t_vector)
- (eql (read-8-bits disk-cache (+ pointer $v_subtype)) subtype)))
-
- (def-predicate consp (p disk-cache pointer)
- (declare (ignore disk-cache))
- (pointer-tagp pointer $t_cons))
-
- (def-predicate listp (p disk-cache pointer)
- (declare (ignore disk-cache))
- (or (eql pointer $pheap-nil)
- (pointer-tagp pointer $t_cons)))
-
- (defun p-atom (p)
- (not (p-consp p)))
-
- (defun dc-atom (disk-cache pointer)
- (not (dc-consp disk-cache pointer)))
-
- (def-predicate uvectorp (p disk-cache pointer)
- (declare (ignore disk-cache))
- (eq $t_vector (pointer-tag pointer)))
-
- (def-predicate packagep (p disk-cache pointer)
- (dc-vector-subtype-p disk-cache pointer $v_pkg))
-
- (def-predicate symbolp (p disk-cache pointer)
- (declare (ignore disk-cache))
- (pointer-tagp pointer $t_symbol))
-
- (def-predicate arrayp (p disk-cache pointer)
- (and (pointer-tagp pointer $t_vector)
- (let ((subtype (dc-%vector-subtype disk-cache pointer)))
- (declare (fixnum subtype))
- (and (<= $v_min_arr subtype) (<= subtype $v_arrayh)))))
-
- (defun dc-array-subtype-satisfies-p (disk-cache array predicate)
- (and (pointer-tagp array $t_vector)
- (let ((subtype (dc-%vector-subtype disk-cache array)))
- (if (eql $v_arrayh subtype)
- (values
- (funcall predicate
- (ccl->wood-subtype (dc-%arrayh-type disk-cache array)))
- t)
- (funcall predicate subtype)))))
-
- (def-predicate stringp (p disk-cache pointer)
- (multiple-value-bind (stringp arrayhp)
- (dc-array-subtype-satisfies-p
- disk-cache pointer
- #'(lambda (x) (eql x $v_sstr)))
- (and stringp
- (or (not arrayhp)
- (eql $arh_one_dim (dc-%arrayh-rank4 disk-cache pointer))))))
-
- (def-predicate vectorp (p disk-cache pointer)
- (multiple-value-bind (arrayp arrayhp)
- (dc-array-subtype-satisfies-p
- disk-cache pointer
- #'(lambda (x)
- (declare (fixnum x))
- (and (<= $v_min_arr x) (< x $v_arrayh))))
- (and arrayp
- (or (not arrayhp)
- (eql $arh_one_dim (dc-%arrayh-rank4 disk-cache pointer))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Accessors
-
- ; Returns vector size in BYTES
- (defun dc-%vector-size (disk-cache v-pointer)
- (read-low-24-bits disk-cache (+ v-pointer $v_log)))
-
- (def-accessor svref (v index) (disk-cache v-pointer)
- (require-satisfies dc-simple-vector-p disk-cache v-pointer)
- (let ((length (dc-%simple-vector-length disk-cache v-pointer)))
- (unless (< -1 index length)
- (error "Index ~s out of bounds in ~s"
- (dc-pointer-pptr disk-cache v-pointer))))
- (dc-%svref disk-cache v-pointer index))
-
- (defun (setf p-svref) (value v index &optional immediate?)
- (declare (ignore value v index immediate?))
- (error "Not implemeneted"))
-
- (defun (setf dc-svref) (value disk-cache v-pointer index &optional immediate?)
- (require-satisfies dc-simple-vector-p disk-cache v-pointer)
- (let ((length (dc-%simple-vector-length disk-cache v-pointer)))
- (unless (< -1 index length)
- (error "Index ~s out of bounds in ~s"
- (dc-pointer-pptr disk-cache v-pointer))))
- (setf (dc-%svref disk-cache v-pointer index immediate?) value))
-
- ; Here's where the $block-overhead is skipped
- (defun addr+ (disk-cache address offset)
- (let* ((page-size (disk-cache-page-size disk-cache))
- (mask (disk-cache-mask disk-cache))
- (start-page 0)
- (page-offset 0)
- (offset (require-type offset 'fixnum)))
- (declare (fixnum page-size mask page-offset blocks-crossed offset))
- (macrolet ((doit ()
- `(progn
- (setq start-page (logand address mask)
- page-offset (- address (incf start-page $block-overhead)))
- (incf page-offset offset)
- (when (>= page-offset (decf page-size $block-overhead))
- (incf page-offset
- (the fixnum (* $block-overhead
- (the fixnum (floor page-offset page-size))))))
- (+ start-page page-offset))))
- ; This will usually be called with fixnum addresses.
- ; It gets called a lot, so the optimization is worthwhile
- (if (fixnump address)
- (locally (declare (fixnum address start-page))
- (doit))
- (doit)))))
-
- (def-accessor ccl::%svref (v index) (disk-cache v-pointer)
- (read-pointer
- disk-cache
- (addr+ disk-cache v-pointer (+ (ash index 2) $v_data))))
-
- (defun (setf p-%svref) (value v index &optional immediate?)
- (declare (ignore value v index immediate?))
- (error "Not implemeneted"))
-
- (defun (setf dc-%svref) (value disk-cache v-pointer index &optional immediate?)
- (setf (read-pointer
- disk-cache
- (addr+ disk-cache v-pointer (+ (ash index 2) $v_data))
- immediate?)
- value))
-
- (defun dc-%simple-vector-length (disk-cache pointer)
- (the fixnum (ash (the fixnum (read-low-24-bits
- disk-cache (+ pointer $v_log)))
- -2)))
-
- (defun dc-%vector-subtype (disk-cache pointer)
- (read-8-bits disk-cache (+ pointer $v_subtype)))
-
- (def-accessor ccl::%vect-subtype (p) (disk-cache pointer)
- (values (dc-%vector-subtype disk-cache pointer) t))
-
- (defun dc-read-fixnum (disk-cache address &optional (address-name address))
- (multiple-value-bind (value imm?) (read-pointer disk-cache address)
- (unless (and imm? (fixnump value))
- (error "Inconsistency: pointer at ~s was not a fixnum." address-name))
- value))
-
- (defun dc-read-cons (disk-cache address &optional (address-name address))
- (multiple-value-bind (value imm?) (read-pointer disk-cache address)
- (unless (and (not imm?) (pointer-tagp value $t_cons))
- (error "Inconsistency: pointer at ~s was not a cons." address-name))
- value))
-
- (defun dc-%svref-fixnum (disk-cache vector index &optional (address-name index))
- (multiple-value-bind (value imm?) (dc-%svref disk-cache vector index)
- (unless (and imm? (fixnump value))
- (error "Inconsistency: pointer at ~s was not a fixnum." address-name))
- value))
-
- (def-accessor car (p) (disk-cache pointer)
- (require-satisfies dc-listp disk-cache pointer)
- (if (eq pointer $pheap-nil)
- $pheap-nil
- (read-pointer disk-cache (- pointer $t_cons))))
-
- (def-accessor cdr (p) (disk-cache pointer)
- (require-satisfies dc-listp disk-cache pointer)
- (if (eq pointer $pheap-nil)
- $pheap-nil
- (read-pointer disk-cache pointer)))
-
- (defun (setf p-car) (value p)
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (v imm?) (%p-store pheap value)
- (setf (dc-car (pheap-disk-cache pheap)
- (pptr-pointer p)
- imm?)
- v)
- (if imm?
- v
- (pptr pheap v))))
- (setf (p-car p) value)))
-
- (defun (setf dc-car) (value disk-cache pointer &optional immediate?)
- (require-satisfies dc-consp disk-cache pointer)
- (setf (read-pointer disk-cache (- pointer $t_cons) immediate?) value))
-
- (defun (setf p-cdr) (value p)
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (v imm?) (%p-store pheap value)
- (setf (dc-cdr (pheap-disk-cache pheap)
- (pptr-pointer p)
- imm?)
- v)
- (if imm?
- v
- (pptr pheap v))))
- (setf (p-car p) value)))
-
- (defun (setf dc-cdr) (value disk-cache pointer &optional immediate?)
- (require-satisfies dc-consp disk-cache pointer)
- (setf (read-pointer disk-cache pointer immediate?) value))
-
- (eval-when (:compile-toplevel :execute)
-
- (defmacro def-cxrs (max-length)
- (let ((res nil)
- (prev '("A" "D"))
- (prev-symbols '(dc-car dc-cdr))
- (len 2)
- next next-symbols)
- (loop
- (loop for middle in prev
- for sym in prev-symbols
- do (loop for prefix in '("A" "D")
- for prefix-symbol in '(dc-car dc-cdr)
- for new-middle = (concatenate 'string prefix middle)
- for name = (intern (concatenate 'string "C" new-middle "R")
- :wood)
- for dc-name = (intern (concatenate 'string "DC-" (symbol-name name))
- :wood)
- for p-name = (intern (concatenate 'string "P-" (symbol-name name))
- :wood)
- for form = `(def-accessor ,name (p) (disk-cache pointer)
- (multiple-value-bind (thing imm?)
- (,sym disk-cache pointer)
- (when imm?
- (error "Immediate returned from:~@
- (~s ~s #x~x).~@
- Expected a cons pointer."
- ',sym disk-cache pointer))
- (,prefix-symbol disk-cache thing)))
- for p-setter = `(defun (setf ,p-name) (value p)
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (v imm?) (%p-store pheap value)
- (setf (,dc-name (pheap-disk-cache pheap)
- (pptr-pointer p)
- imm?)
- v)
- (if imm? v (pptr pheap v))))
- (setf (,name p) value)))
- for dc-setter = `(defun (setf ,dc-name) (value disk-cache pointer &optional
- value-imm?)
- (multiple-value-bind (cons cons-imm?) (,sym disk-cache pointer)
- (when cons-imm?
- (error "(~s ~s ~s) is an immediate."
- ',sym disk-cache pointer))
- (setf (,prefix-symbol disk-cache cons value-imm?) value)))
-
- do
- (push form res)
- (push p-setter res)
- (push dc-setter res)
- (push new-middle next)
- (push dc-name next-symbols)))
- (setq prev next prev-symbols next-symbols
- next nil next-symbols nil)
- (when (> (incf len) max-length) (return)))
- `(progn ,@(nreverse res))))
-
- )
-
- (def-cxrs 4)
-
- (def-accessor uvsize (p) (disk-cache pointer)
- (require-satisfies dc-uvectorp disk-cache pointer)
- (let ((subtype (dc-%vector-subtype disk-cache pointer)))
- (dc-uv-subtype-size subtype
- (dc-%vector-size disk-cache pointer)
- (if (eql $v_bitv subtype)
- (read-8-bits disk-cache (addr+ disk-cache pointer $v_data))))))
-
- (defun dc-uv-subtype-size (subtype bytes &optional last-byte-bits)
- (let* ((bytes-per-element (svref *subtype->bytes-per-element* subtype)))
- (values
- (if bytes-per-element
- (/ bytes bytes-per-element)
- (if (eql $v_bitv subtype)
- (+ (* 8 (- bytes 2)) last-byte-bits)
- (error "~s not supported for vectors of subtype ~s" 'dc-uvref subtype)))
- t)))
-
- (defparameter *subtype->uvreffer*
- #(nil ; 0 - unused
- uvref-unsigned-word ; 1 - $v_bignum
- nil ; 2 - $v_macptr - not supported
- uvref-unsigned-long ; 3 - $v_badptr
- uvref-unsigned-word ; 4 - $v_nlfunv
- nil ; 5 - unused
- nil ; 6 - unused
- uvref-unsigned-byte ; 7 - $v_ubytev - unsigned byte vector
- uvref-unsigned-word ; 8 - $v_uwordv - unsigned word vector
- uvref-dfloat ; 9 - $v_floatv - float vector
- uvref-signed-long ; 10 - $v_slongv - Signed long vector
- uvref-unsigned-long ; 11 - $v_ulongv - Unsigned long vector
- uvref-bit-vector ; 12 - $v_bitv - Bit vector
- uvref-signed-byte ; 13 - $v_sbytev - Signed byte vector
- uvref-signed-word ; 14 - $v_swordv - Signed word vector
- uvref-string ; 15 - $v_sstr - simple string
- uvref-genv ; 16 - $v_genv - simple general vector
- uvref-genv ; 17 - $v_arrayh - complex array header
- uvref-genv ; 18 - $v_struct - structure
- nil ; 19 - $v_mark - buffer mark unimplemented
- uvref-genv ; 20 - $v_pkg
- nil ; 21 - unused
- uvref-genv ; 22 - $v_istruct - type in first element
- uvref-genv ; 23 - $v_ratio
- uvref-genv ; 24 - $v_complex
- uvref-genv ; 25 - $v_instance - clos instance
- nil ; 26 - unused
- nil ; 27 - unused
- nil ; 28 - unused
- uvref-genv ; 29 - $v_weakh - weak list header
- uvref-genv ; 30 - $v_poolfreelist - free pool header
- uvref-genv ; 31 - $v_nhash
- ; WOOD specific subtypes
- uvref-genv ; 32 - $v_area - area descriptor
- uvref-genv ; 33 - $v_segment - area segment
- uvref-unsigned-byte ; 34 - $v_random-bits - vectors of random bits, e.g. resources
- uvref-genv ; 35 - $v_dbheader - database header
- nil ; 36 - $v_segment-headers - specially allocated
- uvref-genv ; 37 - $v_btree
- nil ; 38 - $v_btree-node - specially allocated
- uvref-genv ; 39 - $v_class
- ))
-
- (def-accessor uvref (v index) (disk-cache v-pointer)
- (require-satisfies dc-uvectorp disk-cache v-pointer)
- (let* ((subtype (dc-%vector-subtype disk-cache v-pointer))
- (uvreffer (svref *subtype->uvreffer* subtype)))
- (unless uvreffer
- (error "~s not valid for vector ~s of subtype ~s"
- 'dc-uvref (dc-pointer-pptr disk-cache v-pointer) subtype))
- (funcall uvreffer disk-cache v-pointer index)))
-
- (defun do-uvref (disk-cache pointer offset index reader)
- (let ((size (dc-%vector-size disk-cache pointer)))
- (unless (< -1 offset size)
- (error "Index ~s out of range for ~s"
- index (dc-pointer-pptr disk-cache pointer)))
- (funcall reader disk-cache (addr+ disk-cache pointer (+ $v_data offset)))))
-
- (defun uvref-signed-byte (disk-cache pointer index)
- (values (do-uvref disk-cache pointer index index 'read-8-bits-signed)
- t))
-
- (defun uvref-unsigned-byte (disk-cache pointer index)
- (values (do-uvref disk-cache pointer index index 'read-8-bits)
- t))
-
- (defun uvref-signed-word (disk-cache pointer index)
- (values (do-uvref disk-cache pointer (* 2 index) index 'read-word)
- t))
-
- (defun uvref-unsigned-word (disk-cache pointer index)
- (values (do-uvref disk-cache pointer (* 2 index) index 'read-unsigned-word)
- t))
-
- (defun uvref-signed-long (disk-cache pointer index)
- (values (do-uvref disk-cache pointer (* 4 index) index 'read-long)
- t))
-
- (defun uvref-unsigned-long (disk-cache pointer index)
- (values (do-uvref disk-cache pointer (* 4 index) index 'read-unsigned-long)
- t))
-
- (defun uvref-genv (disk-cache pointer index)
- (do-uvref disk-cache pointer (* 4 index) index 'read-pointer))
-
- (defun uvref-string (disk-cache pointer index)
- (values (code-char (do-uvref disk-cache pointer index index 'read-8-bits))
- t))
-
- ; This will get much less ugly when we can stack cons float vectors.
- (defun uvref-dfloat (disk-cache pointer index)
- (let ((offset (* index 8))
- (size (dc-%vector-size disk-cache pointer)))
- (unless (< -1 offset size)
- (error "Index ~s out of range for ~s"
- index (dc-pointer-pptr disk-cache pointer)))
- (values (read-double-float disk-cache (addr+ disk-cache pointer (+ $v_data offset))) t)))
-
- (defun %bit-vector-index-address-and-bit (disk-cache pointer index)
- (let ((size (dc-uv-subtype-size
- $v_bitv
- (dc-%vector-size disk-cache pointer)
- (read-8-bits disk-cache (addr+ disk-cache pointer $v_data)))))
- (unless (< -1 index size)
- (error "Index ~s out of range for ~s" index (dc-pointer-pptr disk-cache pointer)))
- (values (addr+ disk-cache pointer (+ $v_data 1 (ash index -3)))
- (- 7 (logand index 7)))))
-
- (defun uvref-bit-vector (disk-cache pointer index)
- (multiple-value-bind (address bit)
- (%bit-vector-index-address-and-bit disk-cache pointer index)
- (values
- (if (logbitp bit (read-8-bits disk-cache address))
- 1
- 0)
- t)))
-
-
- (defparameter *subtype->uvsetter*
- #(nil ; 0 - unused
- uvset-word ; 1 - $v_bignum
- nil ; 2 - $v_macptr - not supported
- uvset-long ; 3 - $v_badptr
- uvset-word ; 4 - $v_nlfunv
- nil ; 5 - unused
- nil ; 6 - unused
- uvset-byte ; 7 - $v_ubytev - unsigned byte vector
- uvset-word ; 8 - $v_uwordv - unsigned word vector
- uvset-dfloat ; 9 - $v_floatv - float vector
- uvset-long ; 10 - $v_slongv - Signed long vector
- uvset-long ; 11 - $v_ulongv - Unsigned long vector
- uvset-bit-vector ; 12 - $v_bitv - Bit vector
- uvset-byte ; 13 - $v_sbytev - Signed byte vector
- uvset-word ; 14 - $v_swordv - Signed word vector
- uvset-string ; 15 - $v_sstr - simple string
- uvset-genv ; 16 - $v_genv - simple general vector
- uvset-genv ; 17 - $v_arrayh - complex array header
- uvset-genv ; 18 - $v_struct - structure
- nil ; 19 - $v_mark - buffer mark unimplemented
- uvset-genv ; 20 - $v_pkg
- nil ; 21 - unused
- uvset-genv ; 22 - $v_istruct - type in first element
- uvset-genv ; 23 - $v_ratio
- uvset-genv ; 24 - $v_complex
- uvset-genv ; 25 - $v_instance - clos instance
- nil ; 26 - unused
- nil ; 27 - unused
- nil ; 28 - unused
- uvset-genv ; 29 - $v_weakh - weak list header
- uvset-genv ; 30 - $v_poolfreelist - free pool header
- uvset-genv ; 31 - $v_nhash
- ; WOOD specific subtypes
- uvset-genv ; 32 - $v_area - area descriptor
- uvset-genv ; 33 - $v_segment - area segment
- uvset-byte ; 34 - $v_random-bits - vectors of random bits, e.g. resources
- uvset-genv ; 35 - $v_dbheader - database header
- nil ; 36 - $v_segment-headers - specially allocated
- uvset-genv ; 37 - $v_btree
- nil ; 38 - $v_btree-node - specially allocated
- uvset-genv ; 39 - $v_class
- ))
-
- (defun (setf p-uvref) (value pptr index)
- (if (pptr-p pptr)
- (let ((pheap (pptr-pheap pptr)))
- (multiple-value-bind (value-pointer imm?)
- (if (and (or (bignump value) (typep value 'double-float))
- (memq (svref *subtype->uvsetter* (p-%vect-subtype pptr))
- '(uvset-long uvset-dfloat)))
- (values value t)
- (%p-store pheap value))
- (setf (dc-uvref (pheap-disk-cache pheap)
- (pptr-pointer pptr)
- index
- imm?)
- value-pointer)
- (if imm?
- value-pointer
- (pptr pheap value-pointer))))
- (setf (uvref pptr index) value)))
-
- (defun (setf dc-uvref) (value disk-cache pointer index &optional immediate?)
- (let* ((subtype (dc-%vector-subtype disk-cache pointer))
- (uvsetter (svref *subtype->uvsetter* subtype)))
- (unless uvsetter
- (error "~s not valid for vector ~s of subtype ~s"
- 'dc-uvref (dc-pointer-pptr disk-cache pointer) subtype))
- (funcall uvsetter value disk-cache pointer index immediate?)))
-
- (defun do-uvset (value disk-cache pointer offset index writer immediate?)
- (let ((size (dc-%vector-size disk-cache pointer)))
- (unless (< -1 offset size)
- (error "Index ~s out of range for ~s"
- index (dc-pointer-pptr disk-cache pointer)))
- (if immediate?
- (values (funcall writer
- value disk-cache (addr+ disk-cache pointer (+ $v_data offset)) t)
- t)
- (funcall writer value disk-cache (addr+ disk-cache pointer (+ $v_data offset))))))
-
- (defun uvset-byte (value disk-cache pointer index immediate?)
- (unless (and immediate? (fixnump value))
- (error "Attempt to write a non-fixnum byte"))
- (do-uvset value disk-cache pointer index index #'(setf read-8-bits) nil))
-
- (defun uvset-word (value disk-cache pointer index immediate?)
- (unless (and immediate? (fixnump value))
- (error "Attempt to write a non-fixnum word"))
- (do-uvset value disk-cache pointer (* 2 index) index #'(setf read-word) nil))
-
- (defun uvset-long (value disk-cache pointer index immediate?)
- (unless immediate?
- (setq value (require-type
- (pointer-load (disk-cache-pheap disk-cache) value :default disk-cache)
- 'integer)))
- (do-uvset value disk-cache pointer (* 4 index) index #'(setf read-long) nil))
-
- (defun uvset-genv (value disk-cache pointer index immediate?)
- (do-uvset value disk-cache pointer (* 4 index) index #'(setf read-pointer) immediate?))
-
- (defun uvset-string (value disk-cache pointer index immediate?)
- (declare (ignore immediate?))
- (do-uvset (char-code value) disk-cache pointer index index #'(setf read-8-bits) nil))
-
- (defun uvset-dfloat (value disk-cache pointer index immediate?)
- (let ((offset (* index 8))
- (size (dc-%vector-size disk-cache pointer)))
- (unless (< -1 offset size)
- (error "Index ~s out of range for ~s"
- offset (dc-pointer-pptr disk-cache pointer)))
- (if immediate?
- (setf (read-double-float disk-cache (addr+ disk-cache pointer (+ $v_data offset)))
- (require-type value 'double-float))
- (let ((buf (make-string 8)))
- (declare (dynamic-extent buf))
- (require-satisfies pointer-tagp value $t_dfloat)
- (load-byte-array disk-cache (- value $t_dfloat) 8 buf)
- (store-byte-array buf disk-cache (addr+ disk-cache pointer (+ $v_data offset)) 8)
- value))))
-
- (defun uvset-bit-vector (value disk-cache pointer index immediate?)
- (multiple-value-bind (address bit)
- (%bit-vector-index-address-and-bit disk-cache pointer index)
- (unless (and immediate? (or (eql value 1) (eql value 0)))
- (error "bit vector value must be 0 or 1"))
- (let* ((byte (read-8-bits disk-cache address))
- (set? (logbitp bit byte)))
- (if (eql value 0)
- (when set?
- (setf (read-8-bits disk-cache address)
- (logand byte (lognot (ash 1 bit)))))
- (unless set?
- (setf (read-8-bits disk-cache address)
- (logior byte (ash 1 bit)))))))
- value)
-
- (defun p-array-data-and-offset (p)
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (address offset)
- (dc-array-data-and-offset (pheap-disk-cache pheap)
- (pptr-pointer p))
- (values (pptr pheap address) offset)))
- (ccl::array-data-and-offset p)))
-
- (defun dc-array-data-and-offset (disk-cache pointer)
- (require-satisfies dc-arrayp disk-cache pointer)
- (if (not (dc-vector-subtype-p disk-cache pointer $v_arrayh))
- (values pointer 0)
- (let* ((p pointer)
- (offset 0))
- (loop
- (incf offset (dc-%svref-fixnum disk-cache p $arh.offs '$arh.offs))
- (let ((next-p (dc-%svref disk-cache p $arh.vect)))
- (unless (logbitp $arh_disp_bit (dc-%arrayh-bits disk-cache p))
- (return (values next-p offset)))
- (setq p next-p))))))
-
- (def-accessor length (p) (disk-cache pointer)
- (values
- (cond ((dc-listp disk-cache pointer)
- (dc-%length-of-list disk-cache pointer))
- ((dc-vectorp disk-cache pointer)
- (dc-%vector-length disk-cache pointer))
- (t (error "~s is neither a list nor a vector"
- (dc-pointer-pptr disk-cache pointer))))
- t))
-
- (defun dc-%vector-length (disk-cache pointer)
- (if (eql $v_arrayh (dc-%vector-subtype disk-cache pointer))
- (if (logbitp $arh_fill_bit (dc-%arrayh-bits disk-cache pointer))
- (dc-%svref disk-cache pointer $arh.fill)
- (dc-%svref disk-cache pointer $arh.vlen))
- (dc-uvsize disk-cache pointer)))
-
- (defun dc-%length-of-list (disk-cache pointer)
- (let ((len 0))
- (loop
- (if (eql $pheap-nil pointer)
- (return len))
- (setq pointer (dc-cdr disk-cache pointer))
- (incf len))))
-
- (def-accessor symbol-name (p) (disk-cache pointer)
- (require-satisfies dc-symbolp disk-cache pointer)
- (read-pointer disk-cache (+ pointer $sym_pname)))
-
- (def-accessor symbol-package (p) (disk-cache pointer)
- (require-satisfies dc-symbolp disk-cache pointer)
- (read-pointer disk-cache (+ pointer $sym_package)))
-
- (defun dc-error (string disk-cache pointer)
- (let ((p (dc-pointer-pptr disk-cache pointer)))
- (error string p (p-load p))))
-
- (def-accessor symbol-value (p) (disk-cache pointer)
- (let ((values (dc-symbol-values-list disk-cache pointer)))
- (let ((value (ccl::%unbound-marker-8))
- (value-imm? t))
- (when values
- (multiple-value-setq (value value-imm?) (dc-car disk-cache values)))
- (when (and value-imm? (eq value (ccl::%unbound-marker-8)))
- (dc-error "Unbound variable: ~s = ~s" disk-cache pointer))
- (values value value-imm?))))
-
- ; Should probably take an area parameter
- (defun dc-symbol-values-list (disk-cache pointer &optional create?)
- (require-satisfies dc-symbolp disk-cache pointer)
- (multiple-value-bind (values vv-imm?)
- (read-pointer disk-cache (+ pointer $sym_values))
- (when (or vv-imm? (not (dc-listp disk-cache values)))
- (dc-error "Bad value list for symbol: ~s = ~s" disk-cache pointer))
- (if (eq values $pheap-nil)
- (when create?
- (setf (read-pointer disk-cache (+ pointer $sym_values))
- (dc-make-list disk-cache 2)))
- values)))
-
- (defun (setf p-symbol-value) (value symbol)
- (if (pptr-p symbol)
- (let ((pheap (pptr-pheap symbol)))
- (multiple-value-bind (v v-imm?) (%p-store pheap value)
- (setf (dc-symbol-value (pheap-disk-cache pheap) (pptr-pointer symbol) v-imm?)
- v)
- (if v-imm? v (pptr pheap v))))
- (setf (symbol-value symbol) value)))
-
- (defun (setf dc-symbol-value) (value disk-cache pointer &optional imm?)
- (let ((values (dc-symbol-values-list disk-cache pointer t)))
- (setf (dc-car disk-cache values imm?) value)
- (values value imm?)))
-
- (defun dc-pkg-arg (disk-cache pkg &optional (pkg-imm? (not (integerp pkg))))
- (or (dc-find-package disk-cache pkg pkg-imm?)
- (error "There is no package named ~s"
- (dc-canonicalize-pkg-arg disk-cache pkg pkg-imm?))))
-
- (def-accessor package-name (p) (disk-cache pointer)
- (dc-car disk-cache
- (dc-%svref disk-cache (dc-pkg-arg disk-cache pointer) $pkg.names)))
-
- (def-accessor package-nicknames (p) (disk-cache pointer)
- (dc-cdr disk-cache
- (dc-%svref disk-cache (dc-pkg-arg disk-cache pointer) $pkg.names)))
-
- (def-accessor string (p) (disk-cache pointer)
- (if (dc-stringp disk-cache pointer)
- pointer
- (dc-symbol-name disk-cache pointer)))
-
- (def-accessor array-rank (p) (disk-cache pointer)
- (require-satisfies dc-arrayp disk-cache pointer)
- (values
- (if (dc-vectorp disk-cache pointer)
- 1
- (ash (dc-%arrayh-rank4 disk-cache pointer) -2))
- t))
-
- (def-accessor array-dimension (p n) (disk-cache pointer)
- (let ((rank (dc-array-rank disk-cache pointer)))
- (if (or (not (fixnump n)) (< n 0) (>= n rank))
- (error "~s is non-integer, < 0, or > rank of ~s"
- n (dc-pointer-pptr disk-cache pointer))
- (if (eql 1 rank)
- (dc-%vector-length disk-cache pointer)
- (dc-%svref-fixnum disk-cache pointer (+ $arh.dims n))))))
-
- (def-accessor array-dimensions (p) (disk-cache pointer)
- (let ((rank (dc-array-rank disk-cache pointer)))
- (declare (fixnum rank))
- (if (eql 1 rank)
- (values (list (dc-%vector-length disk-cache pointer)) t)
- (let ((res nil)
- (index $arh.dims))
- (declare (fixnum index))
- (dotimes (i rank)
- (push (dc-%svref-fixnum disk-cache pointer index) res)
- (incf index))
- (values
- (nreverse res)
- t)))))
-
- (defun p-aref (p &rest indices)
- (declare (dynamic-extent indices))
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (res imm?) (dc-aref-internal (pheap-disk-cache pheap)
- (pptr-pointer p)
- indices)
- (if imm?
- res
- (pptr pheap res))))
- (apply #'aref p indices)))
-
- (defun dc-aref (disk-cache pointer &rest indices)
- (declare (dynamic-extent indices))
- (dc-aref-internal disk-cache pointer indices))
-
- ; Clobbers the indices arg. It is a stack-consed rest arg in my uses of it here.
- (defun dc-aref-internal (disk-cache pointer indices)
- (multiple-value-bind (vector index) (dc-aref-vector-and-index disk-cache pointer indices)
- (if (null vector) ; rank 0
- nil
- (dc-uvref disk-cache vector index))))
-
- (defun dc-aref-vector-and-index (disk-cache pointer indices)
- (let ((rank (dc-array-rank disk-cache pointer)))
- (declare (fixnum rank))
- (unless (eql rank (length indices))
- (error "~s cannot be accessed with ~s subscripts."
- (dc-pointer-pptr disk-cache pointer)
- (length indices)))
- (if (eql rank 0)
- nil
- (multiple-value-bind (vector offset) (dc-array-data-and-offset disk-cache pointer)
- (if (eql rank 1)
- (values vector (+ offset (car indices)))
- (let* ((arrayh-index (+ $arh.dims rank -1))
- (index 0)
- (rest-size 1))
- (declare (fixnum index))
- (setq indices (nreverse indices))
- (dotimes (i rank)
- (let ((idx (pop indices))
- (dim (dc-%svref-fixnum disk-cache pointer arrayh-index)))
- (if (>= idx dim)
- (error "Array index ~s out of bounds for ~s"
- idx (dc-pointer-pptr disk-cache pointer)))
- (setq index (+ index (* idx rest-size)))
- (setq rest-size (* rest-size dim))
- (decf arrayh-index)))
- (values vector (+ offset index))))))))
-
- (defun (setf p-aref) (value p &rest indices)
- (declare (dynamic-extent indices))
- (if (pptr-p p)
- (let ((pheap (pptr-pheap p)))
- (multiple-value-bind (v imm?) (%p-store pheap value)
- (dc-setf-aref (pheap-disk-cache pheap) (pptr-pointer p) v imm? indices)
- (if imm?
- v
- (pptr pheap v))))
- (setf (apply #'aref p indices) value)))
-
- (defun dc-setf-aref (disk-cache pointer value value-imm? indices)
- (multiple-value-bind (vector index) (dc-aref-vector-and-index disk-cache pointer indices)
- (setf (dc-uvref disk-cache vector index value-imm?) value)))
-
- #|
- (defun incf-index-list (indices dims)
- (do ((indices-tail indices (cdr indices-tail))
- (dims-tail dims (cdr dims-tail)))
- ((null indices-tail) (return nil))
- (if (>= (incf (car indices-tail)) (car dims-tail))
- (setf (car indices-tail) 0)
- (return indices))))
-
- (defun p-fill-array (array)
- (let* ((dims (p-array-dimensions array))
- (indices (make-list (length dims) :initial-element 0)))
- (loop
- (let ((value (p-store (pptr-pheap array) indices nil)))
- (apply #'(setf p-aref) value array indices))
- (unless (incf-index-list indices dims)
- (return array)))))
-
- (defun p-check-array (array)
- (let* ((dims (p-array-dimensions array))
- (indices (make-list (length dims) :initial-element 0)))
- (loop
- (let ((value (p-load (apply #'p-aref array indices) t)))
- (unless (equal value indices)
- (cerror "Continue."
- "~&SB: ~s, WAS: ~s~%" indices value))
- (unless (incf-index-list indices dims)
- (return))))))
-
- |#
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Consers
- ;;
-
- (defparameter *subtype-initial-element*
- #(nil ; 0 - unused
- nil ; 1 - $v_bignum
- nil ; 2 - $v_macptr not implemented
- nil ; 3 - $v_badptr not implemented
- nil ; 4 - $v_nlfunv
- nil ; 5 - unused
- nil ; 6 - unused
- nil ; 7 - $v_ubytev - unsigned byte vector
- nil ; 8 - $v_uwordv - unsigned word vector
- 0 ; 9 - $v_floatv - float vector
- nil ; 10 - $v_slongv - Signed long vector
- nil ; 11 - $v_ulongv - Unsigned long vector
- nil ; 12 - $v_bitv - Bit vector
- nil ; 13 - $v_sbytev - Signed byte vector
- nil ; 14 - $v_swordv - Signed word vector
- nil ; 15 - $v_sstr - simple string
- #.$pheap-nil ; 16 - $v_genv - simple general vector
- #.$pheap-nil ; 17 - $v_arrayh - complex array header
- #.$pheap-nil ; 18 - $v_struct - structure
- nil ; 19 - $v_mark - buffer mark unimplemented
- #.$pheap-nil ; 20 - $v_pkg
- nil ; 21 - unused
- #.$pheap-nil ; 22 - $v_istruct - type in first element
- 0 ; 23 - $v_ratio
- 0 ; 24 - $v_complex
- #.$pheap-nil ; 25 - $v_instance - clos instance
- nil ; 26 - unused
- nil ; 27 - unused
- nil ; 28 - unused
- #.$pheap-nil ; 29 - $v_weakh - weak list header
- #.$pheap-nil ; 30 - $v_poolfreelist - free pool header
- nil ; 31 - $v_nhash unused
- #.$pheap-nil ; 32 - $v_area - area descriptor
- #.$pheap-nil ; 33 - $v_segment - area segment
- nil ; 34 - $v_random-bits - vectors of random bits, e.g. resources
- #.$pheap-nil ; 35 - $v_dbheader - database header
- nil ; 36 - $v_segment-headers - specially allocated
- #.$pheap-nil ; 37 - $v_btree
- nil ; 38 - $v_btree-node - specially allocated
- #.$pheap-nil ; 39 - $v_class
- ))
-
- (defun initialize-vector-storage (disk-cache address length subtype
- bytes-per-element initial-element
- &optional immediate?)
- (let* ((ptr address)
- (length (require-type length 'fixnum))
- (size (require-type (* length bytes-per-element) 'fixnum))
- (min-disk-cache-size (addr+ disk-cache ptr (+ size $vector-header-size))))
- (declare (fixnum length size))
- (unless (eql 0 (logand 7 ptr))
- (error "Address ~s not double-word aligned" address))
- (unless (typep min-disk-cache-size 'fixnum)
- (error "Attempt to allocate a vector that makes the file too long"))
- (unless (< size (expt 2 24))
- (error "size: ~s > 24 bits") length)
- (extend-disk-cache disk-cache min-disk-cache-size)
- (unless (or (eql bytes-per-element 8)
- (eql bytes-per-element 4)
- (eql bytes-per-element 2)
- (eql bytes-per-element 1))
- (error "~s was ~s, should be 1, 2, or 4"
- 'bytes-per-element bytes-per-element))
- (setf (read-long disk-cache ptr) $vector-header
- (read-8-bits disk-cache (incf ptr 4)) subtype
- (read-low-24-bits disk-cache ptr) size)
- (when initial-element
- (funcall (case bytes-per-element ((4 8) 'fill-long) (2 'fill-word) (1 'fill-byte))
- disk-cache
- (addr+ disk-cache ptr 4)
- initial-element
- ; round up to the nearest double word
- (* (case bytes-per-element ((4 8) 2) (2 4) (1 8))
- (ash (+ size 7) -3))
- immediate?)))
- (+ (the fixnum address) $t_vector))
-
- ; All sizes are rounded up to a multiple of 8 bytes.
- (defmacro normalize-size (x &optional (multiple 8))
- (let ((mask (1- multiple)))
- `(logand (lognot ,mask) (+ ,x ,mask))))
-
- (assert (eql $segment-header-entry-bytes
- (normalize-size $segment-header-entry-bytes)))
-
- ; Make a new area with single segment.
- (defun p-make-area (pheap &rest rest &key segment-size flags)
- (declare (ignore segment-size flags))
- (declare (dynamic-extent rest))
- (pptr pheap (apply #'dc-make-area (pheap-disk-cache pheap) rest)))
-
- (defun dc-make-area (disk-cache &key
- (segment-size *default-area-segment-size*)
- (flags 0))
- (setq segment-size (require-type segment-size 'fixnum)
- flags (require-type flags 'fixnum))
- (symbol-macrolet ((area-header-size (normalize-size (* 4 $area-descriptor-size))))
- (let* ((area (%dc-allocate-new-memory disk-cache 1 $v_area)) ; take 1 page
- (free-count (floor (- (dc-%vector-size disk-cache area) area-header-size)
- $segment-header-entry-bytes))
- (free-ptr (+ area $v_data area-header-size $t_cons
- (- $segment-header-entry-bytes))))
- (assert (typep free-count 'fixnum))
- (dc-%svfill disk-cache area
- $segment-headers.area area
- ; $segment-headers.link is already $pheap-nil
- ($area.flags t) flags
- ($area.segment-size t) segment-size
- $area.last-headers area
- ($area.free-count t) free-count
- $area.free-ptr free-ptr)
- (dc-cons-segment disk-cache area segment-size $pheap-nil)
- area)))
-
- (defmacro with-consing-area (area &body body)
- (let ((thunk (gensym)))
- `(flet ((,thunk () ,@body))
- (declare (dynamic-extend #',thunk))
- (call-with-consing-area #',thunk ,area))))
-
- (defun call-with-consing-area (thunk area)
- (setq area (require-type area 'pptr))
- (let ((pheap (pptr-pheap area))
- (pointer (pptr-pointer area)))
- (require-satisfies dc-vector-subtype-p (pheap-disk-cache pheap) pointer $v_area)
- (let ((old-area (pheap-consing-area pheap)))
- (unwind-protect
- (progn
- (setf (pheap-consing-area pheap) pointer)
- (funcall thunk))
- (setf (pheap-consing-area pheap) old-area)))))
-
- (def-accessor area (p) (disk-cache pointer)
- (let* ((page (logand pointer (disk-cache-mask disk-cache)))
- (segment (read-long disk-cache (+ page $block-segment-ptr))))
- (dc-%svref disk-cache segment $segment.area)))
-
- (defun area (p)
- (declare (ignore p))
- (error "In-memory objects do not have an area.."))
-
-
- ; Cons a new segment for the given area.
- ; The size defaults to the area's segment-size
- ; The free-link parameter is here only for use by dc-make-area above,
- ; so that it doesn't have to inline this code.
- ; Returns the pointer to the segment header.
- (defun dc-cons-segment (disk-cache area &optional segment-size free-link)
- (unless segment-size
- (setq segment-size (dc-%svref disk-cache area $area.segment-size)))
- (let ((free-count (dc-%svref-fixnum disk-cache area $area.free-count '$area.free-count))
- (segment (%dc-allocate-new-memory disk-cache segment-size $v_segment))
- free-ptr)
- (declare (fixnum free-count))
- (flet ((get-free-link (disk-cache free-ptr)
- (if (eql 0 (dc-read-fixnum disk-cache (+ free-ptr $segment-header_freebytes)))
- (dc-read-cons disk-cache (+ free-ptr $segment-header_free-link)
- '$segment-header_free-link)
- free-ptr)))
- (if (> free-count 0)
- (let ((old-free-ptr (dc-%svref disk-cache area $area.free-ptr)))
- (setq free-ptr (+ old-free-ptr $segment-header-entry-bytes)
- free-link (or free-link (get-free-link disk-cache old-free-ptr))
- free-count (1- free-count)))
- (symbol-macrolet ((segment-header-bytes (normalize-size (* 4 $segment-header-size))))
- (let* ((new-headers (%dc-allocate-new-memory disk-cache 1 $v_segment-headers)))
- (setf free-ptr (+ new-headers $v_data segment-header-bytes $t_cons)
- free-link (or free-link
- (get-free-link disk-cache
- (dc-%svref disk-cache area $area.free-ptr)))
- free-count (floor (- (dc-%vector-size disk-cache new-headers)
- segment-header-bytes)
- $segment-header-entry-bytes)
- (dc-%svref disk-cache new-headers $segment-headers.area) area
- ; $segment-headers.link is already $pheap-nil
- (dc-%svref disk-cache
- (dc-%svref disk-cache area $area.last-headers)
- $segment-headers.link)
- new-headers
- (dc-%svref disk-cache area $area.last-headers) new-headers))))
- (dc-%svfill disk-cache segment
- $segment.area area
- $segment.header free-ptr)
- (symbol-macrolet ((segment-header-bytes (normalize-size (* 4 $segment-header-size))))
- (setf (read-pointer disk-cache (+ free-ptr $segment-header_free))
- (+ segment $v_data segment-header-bytes $t_cons)
- (read-pointer disk-cache (+ free-ptr $segment-header_freebytes) t)
- (- (dc-%vector-size disk-cache segment) segment-header-bytes)
- (read-pointer disk-cache (+ free-ptr $segment-header_free-link))
- free-link
- (read-pointer disk-cache (+ free-ptr $segment-header_segment))
- segment))
- (dc-%svfill disk-cache area
- ($area.free-count t) free-count
- $area.free-ptr free-ptr))))
-
- ; This is where the disk file gets longer.
- ; We grow a segment at a time.
- ; Segments are an even multiple of the page size in length and are aligned on a page
- ; boundary.
- ; This fills in only the vector header word and the subtype & length word.
- ; All other initialization must be done by the caller.
- (defun %dc-allocate-new-memory (disk-cache segment-size subtype
- &optional
- (initial-element $pheap-nil)
- ie-imm?)
- (let* ((page-size (disk-cache-page-size disk-cache))
- (page-count (floor (+ segment-size (1- page-size)) page-size)))
- (setq segment-size (* page-count page-size))
- (multiple-value-bind (free-page immediate?)
- (dc-%svref disk-cache $root-vector $pheap.free-page)
- (unless (and immediate? (fixnump free-page))
- (error "Inconsistent PHEAP: free pointer not a fixnum"))
- (setf (dc-%svref disk-cache $root-vector $pheap.free-page t)
- (require-type (+ free-page page-count) 'fixnum))
- (let* ((free (* free-page page-size))
- (data-size (- segment-size (* page-count $block-overhead)))
- (res (initialize-vector-storage
- disk-cache (+ free $block-overhead)
- (ash (- data-size $vector-header-size) -2)
- subtype 4 initial-element ie-imm?)))
- (incf free $block-segment-ptr)
- (dotimes (i page-count)
- (setf (read-pointer disk-cache free) res)
- (incf free page-size))
- res))))
-
- (eval-when (:compile-toplevel :execute)
- (assert (< (expt 2 24) most-positive-fixnum)))
-
- (assert (fixnump (1- (expt 2 24))))
-
- ; And here's where all vectors are consed.
- (defun %cons-vector-in-area (disk-cache area length subtype &optional
- initial-element (immediate? nil))
- (unless initial-element
- (setq initial-element (svref *subtype-initial-element* subtype)))
- (let* ((bytes-per-element (svref *subtype->bytes-per-element* subtype))
- (size (* length bytes-per-element)))
- (unless (< size (expt 2 24))
- (error "Attempt to allocate a vector larger than ~s bytes long"
- (1- (expt 2 24))))
- (locally (declare (fixnum size))
- (let* ((address (%allocate-storage disk-cache area (+ $vector-header-size size))))
- (initialize-vector-storage
- disk-cache (- address $t_cons) length subtype bytes-per-element initial-element
- immediate?)))))
-
- ; Allocate size bytes of storage from the given area.
- ; Does not write anything in the storage.
- ; If you do not fill it properly, the next GC of the pheap will die a horrible death.
- (defun %allocate-storage (disk-cache area size)
- (setq area (maybe-default-disk-cache-area disk-cache area))
- (%allocate-storage-internal
- disk-cache area (dc-%svref disk-cache area $area.free-ptr) (normalize-size size)))
-
- ; Do the work for %allocate-storage
- ; Size must be normalized
- (defun %allocate-storage-internal (disk-cache area segment size &optional
- last-free-segment
- (initial-segment segment)
- it-better-fit)
- (let ((freebytes (dc-read-fixnum disk-cache (+ segment $segment-header_freebytes)
- '$segment-header_freebytes)))
- (declare (fixnum freebytes))
- (if (>= freebytes size)
- ; The allocation fits in this segment
- (let* ((address (dc-read-cons disk-cache (+ segment $segment-header_free))))
- (setf (read-pointer disk-cache (+ segment $segment-header_freebytes) t)
- (decf freebytes size)
- (read-pointer disk-cache (+ segment $segment-header_free))
- (addr+ disk-cache address size))
- (when (and (eql 0 freebytes) last-free-segment)
- ; This segment is full. Splice it out of the free list.
- (setf (read-pointer disk-cache (+ last-free-segment $segment-header_free-link))
- (dc-read-cons disk-cache (+ segment $segment-header_free-link))
- (read-pointer disk-cache (+ segment $segment-header_free-link))
- $pheap-nil))
- address)
- ; Does not fit in this segment, try next free segment
- (let ((free-link (dc-read-cons disk-cache (+ segment $segment-header_free-link))))
- (when it-better-fit
- (error "it-better-fit and it doesn't"))
- (if (not (eql free-link $pheap-nil))
- ; Try the next segment in the free list
- (%allocate-storage-internal
- disk-cache area free-link size segment initial-segment)
- ; Does not fit in any of the existing segments. Make a new one.
- (let ((new-segment (dc-cons-segment
- disk-cache
- area
- (max
- (dc-%svref disk-cache area $area.segment-size)
- (addr+
- disk-cache
- (+ $block-overhead
- (normalize-size (* 4 $segment-header-size))
- $vector-header-size)
- size)))))
- (%allocate-storage-internal
- disk-cache area new-segment size segment initial-segment t)))))))
-
- (defun maybe-default-disk-cache-area (disk-cache area)
- (unless area
- (setq area (dc-default-consing-area disk-cache)))
- (require-satisfies dc-vector-subtype-p disk-cache area $v_area)
- area)
-
- (defun maybe-default-area (pheap area)
- (if area
- (pheap-pptr-pointer area pheap)
- (pheap-consing-area pheap)))
-
- (defun p-cons (pheap car cdr &optional area)
- (multiple-value-bind (car-p car-immediate?) (%p-store pheap car)
- (multiple-value-bind (cdr-p cdr-immediate?) (%p-store pheap cdr)
- (pptr pheap
- (dc-cons (pheap-disk-cache pheap)
- car-p cdr-p car-immediate? cdr-immediate?
- (maybe-default-area pheap area))))))
-
- (defun dc-cons (disk-cache car cdr &optional
- car-immediate? cdr-immediate? area)
- (let ((address (%allocate-storage disk-cache area 8)))
- (setf (read-pointer disk-cache (- address 4) car-immediate?) car
- (read-pointer disk-cache address cdr-immediate?) cdr)
- address))
-
- (defun p-list (pheap &rest elements)
- (declare (dynamic-extent elements))
- (%p-list*-in-area pheap nil elements))
-
- (defun p-list-in-area (pheap area &rest elements)
- (declare (dynamic-extent elements))
- (%p-list*-in-area pheap area elements))
-
- (defun %p-list*-in-area (pheap area elements)
- (let* ((disk-cache (pheap-disk-cache pheap))
- (res $pheap-nil)
- (area-pointer (maybe-default-area pheap area)))
- (require-satisfies dc-vector-subtype-p disk-cache area-pointer $v_area)
- (setq elements (nreverse elements))
- (dolist (element elements)
- (multiple-value-bind (car car-imm?) (%p-store pheap element)
- (setq res (dc-cons disk-cache car res car-imm? nil area-pointer))))
- (pptr pheap res)))
-
- (defun p-make-list (pheap size &key initial-element area)
- (let* ((disk-cache (pheap-disk-cache pheap))
- (area-pointer (maybe-default-area pheap area)))
- (require-satisfies dc-vector-subtype-p disk-cache area-pointer $v_area)
- (multiple-value-bind (ie ie-imm?) (%p-store pheap initial-element)
- (pptr pheap (dc-make-list disk-cache size ie area ie-imm?)))))
-
- (defun dc-make-list (disk-cache size &optional ie area ie-imm?)
- (when (and (null ie) (not ie-imm?))
- (setq ie $pheap-nil))
- (let ((res $pheap-nil))
- (dotimes (i size)
- (setq res (dc-cons disk-cache ie res ie-imm? nil area)))
- res))
-
- (defun p-make-uvector (pheap length subtype &key
- (initial-element nil ie?)
- area)
- (let (ie ie-imm?)
- (when ie?
- (multiple-value-setq (ie ie-imm?) (%p-store pheap initial-element)))
- (pptr pheap
- (dc-make-uvector
- (pheap-disk-cache pheap)
- length
- subtype
- (maybe-default-area pheap area)
- ie ie-imm?))))
-
- (defun dc-make-uvector (disk-cache length &optional
- (subtype $v_genv)
- area
- initial-element
- ie-imm?)
- (setq area (maybe-default-disk-cache-area disk-cache area))
- (if (eql subtype $v_bitv)
- (%cons-bit-vector disk-cache area length initial-element ie-imm?)
- (progn
- (if (and (eq subtype $v_sstr) ie-imm?)
- (setq initial-element (char-code initial-element)))
- (%cons-vector-in-area disk-cache area length subtype initial-element ie-imm?))))
-
- (defun p-make-vector (pheap length &key
- (initial-element nil ie?)
- area)
- (let (ie ie-imm?)
- (when ie?
- (multiple-value-setq (ie ie-imm?) (%p-store pheap initial-element)))
- (pptr pheap
- (dc-make-vector
- (pheap-disk-cache pheap)
- length
- (maybe-default-area pheap area)
- ie ie-imm?))))
-
- (defun dc-make-vector (disk-cache length &optional
- area
- initial-element
- ie-imm?)
- (dc-make-uvector disk-cache length $v_genv area initial-element ie-imm?))
-
- (defun %cons-bit-vector (disk-cache area length &optional initial-element ie-imm?)
- (let* ((bytes (1+ (ceiling length 8))))
- (unless (< bytes (expt 2 24))
- (error "Attempt to allocate a vector larger than ~s bytes long"
- (1- (expt 2 24))))
- (when initial-element
- (unless ie-imm?
- (error "Attempt to create a bit-vector with a non-bit initial-element."))
- (ecase initial-element
- (0)
- (1 (setq initial-element #xff))))
- (locally (declare (fixnum bytes))
- (let* ((address (%allocate-storage disk-cache area (+ $vector-header-size bytes)))
- (res (initialize-vector-storage
- disk-cache (- address $t_cons) bytes $v_bitv 1
- initial-element ie-imm?)))
- (setf (read-8-bits disk-cache (addr+ disk-cache res $v_data)) (mod length 8))
- res))))
-
- (defun p-make-array (pheap dimensions &key
- area
- (element-type t)
- initial-contents
- initial-element
- adjustable
- fill-pointer
- displaced-to
- displaced-index-offset)
- (let (ie ie-imm?)
- (when initial-element ; NIL is the default
- (multiple-value-setq (ie ie-imm?) (%p-store pheap initial-element)))
- (pptr pheap
- (dc-make-array
- (pheap-disk-cache pheap)
- (p-load dimensions)
- (if (pptr-p area)
- (pheap-pptr-pointer area pheap)
- (pheap-consing-area pheap))
- (p-load element-type)
- ie
- ie-imm?
- initial-contents
- adjustable
- fill-pointer
- displaced-to
- displaced-index-offset))))
-
- (defun dc-make-array (disk-cache dimensions &optional
- area (element-type t) initial-element ie-imm?
- initial-contents adjustable
- fill-pointer displaced-to
- displaced-index-offset)
- (when (or initial-contents adjustable fill-pointer
- displaced-to displaced-index-offset)
- (error "Unsupported array option. Only support :initial-element & :area"))
- (let ((subtype (array-element-type->subtype element-type)))
- (if (or (atom dimensions) (null (cdr dimensions)))
- ; one-dimensional array
- (let ((length (require-type
- (if (atom dimensions) dimensions (car dimensions))
- 'fixnum)))
- (dc-make-uvector disk-cache length subtype area initial-element ie-imm?))
- ; multi-dimensional array
- (progn
- (dolist (dim dimensions)
- (unless (and (fixnump dim) (>= dim 0))
- (error "Array dimension not a fixnum or less than 0: ~s")))
- (let ((rank (length dimensions))
- (length (apply #'* dimensions)))
- (unless (fixnump length)
- (error "Attempt to create multidimensional of size > ~s"
- most-positive-fixnum))
- (unless (< rank (/ (expt 2 15) 4))
- (error "rank ~s > (/ (expt 2 15) 4)" rank))
- (let ((vector (dc-make-uvector
- disk-cache length subtype area initial-element ie-imm?))
- (arrayh (dc-make-uvector disk-cache (+ $arh.dims rank) $v_arrayh area 0 t)))
- (setf (dc-%svref disk-cache arrayh $arh.vect) vector
- (dc-%arrayh-rank4 disk-cache arrayh) (* 4 rank)
- (dc-%arrayh-type disk-cache arrayh) (wood->ccl-subtype subtype)
- (dc-%arrayh-bits disk-cache arrayh) (ash 1 $arh_simple_bit))
- (let ((dims dimensions)
- (index $arh.dims))
- (declare (fixnum index))
- (dotimes (i (the fixnum rank))
- (setf (dc-%svref disk-cache arrayh index t) (pop dims))
- (incf index)))
- arrayh))))))
-
-
- (defparameter *array-element-type->subtype*
- '((bit . #.$v_bitv)
- ((signed-byte 8) . #.$v_sbytev)
- ((unsigned-byte 8) . #.$v_ubytev)
- ((signed-byte 16) . #.$v_swordv)
- ((unsigned-byte 16) . #.$v_uwordv)
- ((signed-byte 32) . #.$v_slongv)
- ((unsigned-byte 32) . #.$v_ulongv)
- (double-float . #.$v_floatv)
- (character . #.$v_sstr)
- (t . #.$v_genv)))
-
- (defun array-element-type->subtype (element-type)
- (if (eq element-type t)
- $v_genv
- (dolist (pair *array-element-type->subtype*
- (error "Can't find subtype. Shouldn't happen."))
- (if (subtypep element-type (car pair))
- (return (cdr pair))))))
-
- (defun p-vector (pheap &rest elements)
- (declare (dynamic-extent elements))
- (p-uvector* pheap $v_genv elements))
-
- (defun p-uvector (pheap subtype &rest elements)
- (declare (dynamic-extent elements))
- (p-uvector* pheap subtype elements))
-
- (defun p-uvector* (pheap subtype elements)
- (let* ((genv? (eql (svref *subtype->uvsetter* subtype) 'uvset-genv))
- (vector (p-make-uvector pheap (length elements) subtype))
- (disk-cache (pheap-disk-cache pheap))
- (vector-pointer (pptr-pointer vector))
- (i 0))
- (if genv?
- (dolist (element elements)
- (multiple-value-bind (e imm?) (%p-store pheap element)
- (setf (dc-%svref disk-cache vector-pointer i imm?) e)
- (incf i)))
- (dolist (element elements)
- (multiple-value-bind (e imm?) (%p-store pheap element)
- (setf (dc-uvref disk-cache vector-pointer i imm?) e)
- (incf i))))
- vector))
-
- (defun p-cons-population (pheap data &optional (type 0))
- (p-uvector pheap $v_weakh nil type data))
-
- (def-accessor ccl::population-data (p) (disk-cache pointer)
- (require-satisfies dc-vector-subtype-p disk-cache pointer $v_weakh)
- (dc-%svref disk-cache pointer $population.data))
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Packages and symbols
- ;;;
-
- (defun p-find-package (pheap package)
- (if (and (pptr-p package)
- (p-packagep package))
- package
- (multiple-value-bind (pkg pkg-imm?) (split-pptr package)
- (let ((pointer (dc-find-package (pheap-disk-cache pheap) pkg pkg-imm?)))
- (when pointer
- (pptr pheap pointer))))))
-
- ; Returns a disk-resident package, memory-resident package, or memory-resident string
- (defun dc-canonicalize-pkg-arg (disk-cache pkg pkg-imm?)
- (if pkg-imm?
- (values
- (if (packagep pkg)
- pkg
- (string pkg))
- t)
- (if (dc-packagep disk-cache pkg)
- pkg
- (values (pointer-load (disk-cache-pheap disk-cache)
- (dc-string disk-cache pkg)
- :default
- disk-cache)
- t))))
-
- (defun dc-find-package (disk-cache pkg &optional pkg-imm?)
- (multiple-value-bind (pkg pkg-imm?) (dc-canonicalize-pkg-arg disk-cache pkg pkg-imm?)
- (if (not pkg-imm?)
- pkg
- (let* ((pkg-name (if (packagep pkg)
- (package-name pkg)
- (string pkg)))
- (btree (dc-package-btree disk-cache nil)))
- (and btree
- (dc-btree-lookup disk-cache btree pkg-name))))))
-
- (defun p-package-btree (pheap &optional (create? t))
- (let ((pointer (dc-package-btree (pheap-disk-cache pheap) create?)))
- (and pointer (pptr pheap pointer))))
-
- (defun dc-package-btree (disk-cache &optional (create? t))
- (let ((btree (dc-%svref disk-cache $root-vector $pheap.package-btree)))
- (if (not (eql $pheap-nil btree))
- btree
- (when create?
- (setf (dc-%svref disk-cache $root-vector $pheap.package-btree)
- (dc-make-btree disk-cache))))))
-
- (defun p-make-package (pheap package-name &key nicknames)
- (pptr pheap (dc-make-package (pheap-disk-cache pheap)
- (p-load package-name)
- (p-load nicknames))))
-
- (defun dc-make-package (disk-cache name &optional nicknames)
- (let* ((pkg-name (ensure-simple-string (string name)))
- (btree (dc-package-btree disk-cache)))
- (if (dc-btree-lookup disk-cache btree pkg-name)
- (error "package name ~s already in use in ~s"
- pkg-name (disk-cache-pheap disk-cache))
- (dc-btree-store
- disk-cache
- btree
- pkg-name
- (dc-cons-package disk-cache pkg-name nicknames)))))
-
- (defun p-cons-package (pheap pkg-name &optional nicknames)
- (pptr pheap
- (dc-cons-package (pheap-disk-cache pheap)
- (p-load pkg-name)
- (p-load nicknames)
- pheap)))
-
- (defun dc-cons-package (disk-cache pkg-name &optional
- nicknames
- (pheap (disk-cache-pheap disk-cache)))
- (let* ((names (mapcar #'(lambda (x) (ensure-simple-string (string x)))
- (cons pkg-name nicknames)))
- (p-names (%p-store pheap names))
- (package (dc-make-uvector disk-cache $pkg-length $v_pkg)))
- (setf (dc-uvref disk-cache package $pkg.names) p-names
- (dc-uvref disk-cache package $pkg.btree) (dc-make-btree disk-cache))
- package))
-
-
- (defun p-intern (pheap string &key
- (package *package*)
- (area nil area-p))
- (multiple-value-bind (pkg pkg-imm?) (split-pptr package)
- (pptr pheap (dc-intern (pheap-disk-cache pheap)
- (p-load string)
- pkg pkg-imm?
- (if area-p
- (pheap-pptr-pointer area pheap)
- (pheap-consing-area pheap))
- pheap))))
-
- (defun dc-intern (disk-cache string pkg &optional pkg-imm? area pheap)
- (let* ((pkg (dc-find-or-make-package disk-cache pkg pkg-imm?))
- (str (require-type string 'string))
- (btree (dc-%svref disk-cache pkg $pkg.btree)))
- (or (dc-btree-lookup disk-cache btree str)
- (dc-btree-store
- disk-cache
- btree
- (setq str (ensure-simple-string str))
- (dc-cons-symbol disk-cache
- (%p-store (or pheap (disk-cache-pheap disk-cache)) str)
- pkg area)))))
-
- (defun dc-find-or-make-package (disk-cache package &optional pkg-imm?)
- (multiple-value-bind (pkg pkg-imm?)
- (dc-canonicalize-pkg-arg disk-cache package pkg-imm?)
- (or (dc-find-package disk-cache pkg pkg-imm?)
- (let* ((pkg (or (if (packagep package) package (find-package package))
- (error "There is no package named ~s package")))
- (pkg-name (package-name pkg))
- (nicknames (package-nicknames pkg)))
- (dc-make-package disk-cache pkg-name nicknames)))))
-
- (defun dc-cons-symbol (disk-cache string-pointer package &optional area)
- (let ((sym (+ (- $t_symbol $t_cons)
- (%allocate-storage disk-cache area $symbol-size))))
- (setf (read-long disk-cache (+ sym $sym_header)) $symbol-header
- (read-long disk-cache (+ sym $sym_pname)) string-pointer
- (read-long disk-cache (+ sym $sym_package)) package
- (read-long disk-cache (+ sym $sym_values)) $pheap-nil)
- sym))
-
- (defun p-find-symbol (pheap string &optional (package *package*))
- (multiple-value-bind (pkg pkg-imm?) (split-pptr package)
- (let ((pointer (dc-find-symbol (pheap-disk-cache pheap) string pkg pkg-imm?)))
- (and pointer (pptr pheap pointer)))))
-
- (defun dc-find-symbol (disk-cache string &optional (package *package*) pkg-imm?)
- (let* ((pkg (dc-find-package disk-cache package pkg-imm?))
- (str (require-type string 'string)))
- (and pkg
- (dc-btree-lookup disk-cache
- (dc-%svref disk-cache pkg $pkg.btree)
- str))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Hash tables
- ;;;
-
- (defun p-make-hash-table (pheap &key (test 'eq) weak area)
- (pptr pheap (dc-make-hash-table
- (pheap-disk-cache pheap)
- :test test
- :weak weak
- :area (maybe-default-area pheap area))))
-
- (defun dc-make-hash-table (disk-cache &key (test 'eq) weak area)
- (unless (or (eq test 'eq) (eq test #'eq))
- (error "Only ~s hash tables supported" 'eq))
- (let ((type (ecase weak
- ((nil) $btree-type_eqhash)
- (:key $btree-type_eqhash-weak-key)
- (:value $btree-type_eqhash-weak-value))))
- (dc-make-btree disk-cache area type)))
-
- (defun p-btree-p (p)
- (and (pptr-p p)
- (dc-btree-p (pptr-disk-cache p) (pptr-pointer p))))
-
- (defun dc-btree-p (disk-cache pointer)
- (dc-vector-subtype-p disk-cache pointer $v_btree))
-
- (def-predicate hash-table-p (p disk-cache pointer)
- (and (dc-btree-p disk-cache pointer)
- (> (dc-uvsize disk-cache pointer) $btree.type) ; early versions missing this slot
- (logbitp $btree-type_eqhash-bit
- (dc-%svref-fixnum disk-cache pointer $btree.type '$btree.type))))
-
- (def-accessor hash-table-count (p) (disk-cache pointer)
- (require-satisfies dc-hash-table-p disk-cache pointer)
- (dc-btree-count disk-cache pointer))
-
- (def-accessor btree-count (p) (disk-cache pointer)
- (require-satisfies dc-btree-p disk-cache pointer)
- (dc-%svref disk-cache pointer $btree.count))
-
- (defun btree-count (p)
- (declare (ignore p))
- (error "~s is only defined for wood btrees" 'btree-count))
-
- (defun wood-immediate-p (object)
- (svref #(t ; $t_fixnum
- nil ; $t_vector
- nil ; $t_symbol
- nil ; $t_dfloat
- nil ; $t_cons
- t ; $t_sfloat
- nil ; $t_lfun
- t) ; $t_imm
- (ccl::%ttag object)))
-
- (defun p-gethash (key hash &optional default)
- (if (pptr-p hash)
- (let* ((pheap (pptr-pheap hash))
- (hash-pointer (pptr-pointer hash))
- (disk-cache (pheap-disk-cache pheap)))
- (require-satisfies dc-hash-table-p disk-cache hash-pointer)
- (multiple-value-bind (value imm?) (%p-store-hash-key pheap key)
- (multiple-value-bind (res res-imm? found?)
- (and value
- (dc-gethash disk-cache value imm? hash-pointer))
- (if found?
- (values
- (if res-imm?
- res
- (pptr pheap res))
- t)
- default))))
- (gethash key hash default)))
-
- ; This could be just %p-store, but I'd rather not look in the
- ; btree if I know that the key can't be EQ.
- (defun %p-store-hash-key (pheap key)
- (if (pptr-p key)
- (pheap-pptr-pointer key pheap)
- (cond ((wood-immediate-p key) (values key t))
- ((null key) $pheap-nil)
- (t
- (maybe-cached-address pheap key
- ; This will be slightly faster if the p-find-xxx's are changed
- ; to dc-find-xxx.
- (or (cond ((symbolp key)
- (split-pptr (p-find-symbol
- pheap (symbol-name key) (symbol-package key))))
- ((packagep key)
- (split-pptr (p-find-package pheap key)))
- ((typep key 'class)
- (split-pptr (p-find-class pheap key nil))))
- (return-from %p-store-hash-key nil)))))))
-
-
- (defmacro with-dc-hash-key ((key-var key key-imm?) &body body)
- (let ((s4 (gensym))
- (s3 (gensym))
- (s2 (gensym))
- (s1 (gensym)))
- `(let* ((,s4 (make-string 4))
- (,s3 (make-string 3))
- (,s2 (make-string 2))
- (,s1 (make-string 1))
- ,key-var)
- (declare (dynamic-extent ,s4 ,s3 ,s2 ,s1))
- (%store-pointer ,key ,s4 0 ,key-imm?)
- (locally (declare (optimize (speed 3) (safety 0)))
- (if (eql #\000 (schar ,s4 0))
- (if (eql #\000 (schar ,s4 1))
- (if (eql #\000 (schar ,s4 2))
- (setf (schar ,s1 0) (schar ,s4 3)
- ,key-var ,s1)
- (setf (schar ,s2 0) (schar ,s4 2)
- (schar ,s2 1) (schar ,s4 3)
- ,key-var ,s2))
- (setf (schar ,s3 0) (schar ,s4 1)
- (schar ,s3 1) (schar ,s4 2)
- (schar ,s3 2) (schar ,s4 3)
- ,key-var ,s3))
- (setq ,key-var ,s4)))
- ,@body)))
-
- (defun dc-hash-key-value (key-string)
- (let* ((s (make-string 4))
- (len (length key-string)))
- (declare (dynamic-extent s)
- (fixnum len))
- (locally (declare (optimize (speed 3) (safety 0)))
- (setf (schar s 0)
- (setf (schar s 1)
- (setf (schar s 2)
- (setf (schar s 3) #\000)))))
- (if (> len 4) (error "Bad hash-table key-string: ~s" key-string))
- (%copy-byte-array-portion key-string 0 len s (the fixnum (- 4 len)))
- (%load-pointer s 0)))
-
- (defun dc-gethash (disk-cache key key-imm? hash)
- (with-dc-hash-key (key-string key key-imm?)
- (dc-btree-lookup disk-cache hash key-string)))
-
- (defun (setf p-gethash) (value key hash &optional default)
- (declare (ignore default))
- (if (pptr-p hash)
- (let* ((pheap (pptr-pheap hash))
- (hash-pointer (pptr-pointer hash))
- (disk-cache (pheap-disk-cache pheap)))
- (require-satisfies dc-hash-table-p disk-cache hash-pointer)
- (multiple-value-bind (vp vi?) (%p-store pheap value)
- (multiple-value-bind (kp ki?) (%p-store pheap key)
- (dc-puthash disk-cache kp ki? hash-pointer vp vi?)
- (if vi?
- vp
- (pptr pheap vp)))))
- (setf (gethash key hash) value)))
-
- (defun dc-puthash (disk-cache key key-imm? hash value &optional value-imm?)
- (with-dc-hash-key (key-string key key-imm?)
- (dc-btree-store disk-cache hash key-string value value-imm?)))
-
- (defun p-remhash (key hash)
- (if (pptr-p hash)
- (let ((pheap (pptr-pheap hash)))
- (multiple-value-bind (value imm?) (%p-store-hash-key pheap key)
- (dc-remhash (pheap-disk-cache pheap) value imm? (pptr-pointer hash))))
- (remhash key hash)))
-
- (defun dc-remhash (disk-cache key key-imm? hash)
- (with-dc-hash-key (key-string key key-imm?)
- (dc-btree-delete disk-cache hash key-string)))
-
- (defun p-clrhash (hash)
- (if (pptr-p hash)
- (progn
- (dc-clrhash (pptr-disk-cache hash) (pptr-pointer hash))
- hash)
- (clrhash hash)))
-
- (defun dc-clrhash (disk-cache hash)
- (dc-clear-btree disk-cache hash))
-
- (defun p-maphash (function hash)
- (if (pptr-p hash)
- (let* ((pheap (pptr-pheap hash))
- (f #'(lambda (disk-cache key value value-imm?)
- (declare (ignore disk-cache))
- (multiple-value-bind (key-value key-imm?) (dc-hash-key-value key)
- (funcall function
- (if key-imm? key-value (pptr pheap key-value))
- (if value-imm? value (pptr pheap value)))))))
- (declare (dynamic-extent f))
- (dc-map-btree (pheap-disk-cache pheap) (pptr-pointer hash) f))
- (maphash function hash)))
-
- #|
-
- ; Remove a pptr from the caches.
- ; Used while debugging p-xxx accessors
- (defun pptr-decache (pptr)
- (let* ((pheap (pptr-pheap pptr))
- (pointer (pptr-pointer pptr))
- (pheap->mem-hash (pheap->mem-hash pheap)))
- (multiple-value-bind (value found) (gethash pointer pheap->mem-hash)
- (when found
- (remhash pointer pheap->mem-hash)
- (remhash value (mem->pheap-hash pheap))))))
-
-
- (defun init-temp-pheap ()
- (declare (special pheap dc))
- (when (boundp 'pheap)
- (close-pheap pheap))
- (delete-file "temp.pheap")
- (create-pheap "temp.pheap")
- (setq pheap (open-pheap "temp.pheap")
- dc (pheap-disk-cache pheap))
- (dolist (w (windows :class 'inspector::inspector-window))
- (window-close w))
- (inspect dc))
-
- (setq p $pheap-nil)
-
- (time
- (dotimes (i 200)
- (setq p (dc-cons dc i p t nil))))
-
- (time
- (dotimes (i 1000)
- (setq p (dc-make-uvector dc 12 $v_genv nil p))))
-
- (defun crash-close (pheap)
- (let ((disk-cache (pheap-disk-cache pheap)))
- (close (disk-cache-stream disk-cache))
- (setq *open-disk-caches* (delq disk-cache *open-disk-caches*)
- *open-pheaps* (delq pheap *open-pheaps*)))
- nil)
-
- |#